Commit 0afc2edf authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6:
  [SPARC32]: Use regsets in arch_ptrace().
  [SPARC64]: Use regsets in arch_ptrace().
  [SPARC32]: Use regsets for ELF core dumping.
  [SPARC64]: Use regsets for ELF core dumping.
  [SPARC64]: Remove unintentional ptrace debugging messages.
  [SPARC]: Move over to arch_ptrace().
  [SPARC]: Remove PTRACE_SUN* handling.
  [SPARC]: Kill DEBUG_PTRACE code.
  [SPARC32]: Add user regset support.
  [SPARC64]: Add user regsets.
  [SPARC64]: Fix booting on non-zero cpu.
parents a8e98d6d d256eb8d
...@@ -1224,23 +1224,6 @@ sys_nis_syscall: ...@@ -1224,23 +1224,6 @@ sys_nis_syscall:
call c_sys_nis_syscall call c_sys_nis_syscall
mov %l5, %o7 mov %l5, %o7
.align 4
.globl sys_ptrace
sys_ptrace:
call do_ptrace
add %sp, STACKFRAME_SZ, %o0
ld [%curptr + TI_FLAGS], %l5
andcc %l5, _TIF_SYSCALL_TRACE, %g0
be 1f
nop
call syscall_trace
nop
1:
RESTORE_ALL
.align 4 .align 4
.globl sys_execve .globl sys_execve
sys_execve: sys_execve:
......
/* ptrace.c: Sparc process tracing support. /* ptrace.c: Sparc process tracing support.
* *
* Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net)
* *
* Based upon code written by Ross Biro, Linus Torvalds, Bob Manson, * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
* and David Mosberger. * and David Mosberger.
...@@ -19,389 +19,343 @@ ...@@ -19,389 +19,343 @@
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/regset.h>
#include <linux/elf.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#define MAGIC_CONSTANT 0x80000000 /* #define ALLOW_INIT_TRACING */
/* Returning from ptrace is a bit tricky because the syscall return /*
* low level code assumes any value returned which is negative and * Called by kernel/ptrace.c when detaching..
* is a valid errno will mean setting the condition codes to indicate *
* an error return. This doesn't work, so we have this hook. * Make sure single step bits etc are not set.
*/ */
static inline void pt_error_return(struct pt_regs *regs, unsigned long error) void ptrace_disable(struct task_struct *child)
{ {
regs->u_regs[UREG_I0] = error; /* nothing to do */
regs->psr |= PSR_C;
regs->pc = regs->npc;
regs->npc += 4;
} }
static inline void pt_succ_return(struct pt_regs *regs, unsigned long value) enum sparc_regset {
{ REGSET_GENERAL,
regs->u_regs[UREG_I0] = value; REGSET_FP,
regs->psr &= ~PSR_C; };
regs->pc = regs->npc;
regs->npc += 4;
}
static void static int genregs32_get(struct task_struct *target,
pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long __user *addr) const struct user_regset *regset,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{ {
if (put_user(value, addr)) { const struct pt_regs *regs = target->thread.kregs;
pt_error_return(regs, EFAULT); unsigned long __user *reg_window;
return; unsigned long *k = kbuf;
unsigned long __user *u = ubuf;
unsigned long reg;
if (target == current)
flush_user_windows();
pos /= sizeof(reg);
count /= sizeof(reg);
if (kbuf) {
for (; count > 0 && pos < 16; count--)
*k++ = regs->u_regs[pos++];
reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
for (; count > 0 && pos < 32; count--) {
if (get_user(*k++, &reg_window[pos++]))
return -EFAULT;
}
} else {
for (; count > 0 && pos < 16; count--) {
if (put_user(regs->u_regs[pos++], u++))
return -EFAULT;
}
reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
for (; count > 0 && pos < 32; count--) {
if (get_user(reg, &reg_window[pos++]) ||
put_user(reg, u++))
return -EFAULT;
}
} }
regs->u_regs[UREG_I0] = 0; while (count > 0) {
regs->psr &= ~PSR_C; switch (pos) {
regs->pc = regs->npc; case 32: /* PSR */
regs->npc += 4; reg = regs->psr;
} break;
case 33: /* PC */
reg = regs->pc;
break;
case 34: /* NPC */
reg = regs->npc;
break;
case 35: /* Y */
reg = regs->y;
break;
case 36: /* WIM */
case 37: /* TBR */
reg = 0;
break;
default:
goto finish;
}
static void if (kbuf)
pt_os_succ_return (struct pt_regs *regs, unsigned long val, long __user *addr) *k++ = reg;
{ else if (put_user(reg, u++))
if (current->personality == PER_SUNOS) return -EFAULT;
pt_succ_return (regs, val); pos++;
else count--;
pt_succ_return_linux (regs, val, addr); }
finish:
pos *= sizeof(reg);
count *= sizeof(reg);
return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
38 * sizeof(reg), -1);
} }
/* Fuck me gently with a chainsaw... */ static int genregs32_set(struct task_struct *target,
static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset, const struct user_regset *regset,
struct task_struct *tsk, long __user *addr) unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{ {
struct pt_regs *cregs = tsk->thread.kregs; struct pt_regs *regs = target->thread.kregs;
struct thread_info *t = task_thread_info(tsk); unsigned long __user *reg_window;
int v; const unsigned long *k = kbuf;
const unsigned long __user *u = ubuf;
if(offset >= 1024) unsigned long reg;
offset -= 1024; /* whee... */
if(offset & ((sizeof(unsigned long) - 1))) { if (target == current)
pt_error_return(regs, EIO); flush_user_windows();
return;
} pos /= sizeof(reg);
if(offset >= 16 && offset < 784) { count /= sizeof(reg);
offset -= 16; offset >>= 2;
pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr); if (kbuf) {
return; for (; count > 0 && pos < 16; count--)
} regs->u_regs[pos++] = *k++;
if(offset >= 784 && offset < 832) {
offset -= 784; offset >>= 2; reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr); for (; count > 0 && pos < 32; count--) {
return; if (put_user(*k++, &reg_window[pos++]))
} return -EFAULT;
switch(offset) { }
case 0: } else {
v = t->ksp; for (; count > 0 && pos < 16; count--) {
break; if (get_user(reg, u++))
case 4: return -EFAULT;
v = t->kpc; regs->u_regs[pos++] = reg;
break; }
case 8:
v = t->kpsr;
break;
case 12:
v = t->uwinmask;
break;
case 832:
v = t->w_saved;
break;
case 896:
v = cregs->u_regs[UREG_I0];
break;
case 900:
v = cregs->u_regs[UREG_I1];
break;
case 904:
v = cregs->u_regs[UREG_I2];
break;
case 908:
v = cregs->u_regs[UREG_I3];
break;
case 912:
v = cregs->u_regs[UREG_I4];
break;
case 916:
v = cregs->u_regs[UREG_I5];
break;
case 920:
v = cregs->u_regs[UREG_I6];
break;
case 924:
if(tsk->thread.flags & MAGIC_CONSTANT)
v = cregs->u_regs[UREG_G1];
else
v = 0;
break;
case 940:
v = cregs->u_regs[UREG_I0];
break;
case 944:
v = cregs->u_regs[UREG_I1];
break;
case 948: reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
/* Isn't binary compatibility _fun_??? */ for (; count > 0 && pos < 32; count--) {
if(cregs->psr & PSR_C) if (get_user(reg, u++) ||
v = cregs->u_regs[UREG_I0] << 24; put_user(reg, &reg_window[pos++]))
else return -EFAULT;
v = 0; }
break; }
while (count > 0) {
unsigned long psr;
if (kbuf)
reg = *k++;
else if (get_user(reg, u++))
return -EFAULT;
switch (pos) {
case 32: /* PSR */
psr = regs->psr;
psr &= ~PSR_ICC;
psr |= (reg & PSR_ICC);
regs->psr = psr;
break;
case 33: /* PC */
regs->pc = reg;
break;
case 34: /* NPC */
regs->npc = reg;
break;
case 35: /* Y */
regs->y = reg;
break;
case 36: /* WIM */
case 37: /* TBR */
break;
default:
goto finish;
}
/* Rest of them are completely unsupported. */ pos++;
default: count--;
printk("%s [%d]: Wants to read user offset %ld\n",
current->comm, task_pid_nr(current), offset);
pt_error_return(regs, EIO);
return;
} }
if (current->personality == PER_SUNOS) finish:
pt_succ_return (regs, v); pos *= sizeof(reg);
else count *= sizeof(reg);
pt_succ_return_linux (regs, v, addr);
return; return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
38 * sizeof(reg), -1);
} }
static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset, static int fpregs32_get(struct task_struct *target,
struct task_struct *tsk) const struct user_regset *regset,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{ {
struct pt_regs *cregs = tsk->thread.kregs; const unsigned long *fpregs = target->thread.float_regs;
struct thread_info *t = task_thread_info(tsk); int ret = 0;
unsigned long value = regs->u_regs[UREG_I3];
if(offset >= 1024)
offset -= 1024; /* whee... */
if(offset & ((sizeof(unsigned long) - 1)))
goto failure;
if(offset >= 16 && offset < 784) {
offset -= 16; offset >>= 2;
*(((unsigned long *)(&t->reg_window[0]))+offset) = value;
goto success;
}
if(offset >= 784 && offset < 832) {
offset -= 784; offset >>= 2;
*(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value;
goto success;
}
switch(offset) {
case 896:
cregs->u_regs[UREG_I0] = value;
break;
case 900:
cregs->u_regs[UREG_I1] = value;
break;
case 904:
cregs->u_regs[UREG_I2] = value;
break;
case 908:
cregs->u_regs[UREG_I3] = value;
break;
case 912:
cregs->u_regs[UREG_I4] = value;
break;
case 916:
cregs->u_regs[UREG_I5] = value;
break;
case 920:
cregs->u_regs[UREG_I6] = value;
break;
case 924:
cregs->u_regs[UREG_I7] = value;
break;
case 940:
cregs->u_regs[UREG_I0] = value;
break;
case 944:
cregs->u_regs[UREG_I1] = value;
break;
/* Rest of them are completely unsupported or "no-touch". */ #if 0
default: if (target == current)
printk("%s [%d]: Wants to write user offset %ld\n", save_and_clear_fpu();
current->comm, task_pid_nr(current), offset); #endif
goto failure;
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
fpregs,
0, 32 * sizeof(u32));
if (!ret)
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
32 * sizeof(u32),
33 * sizeof(u32));
if (!ret)
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&target->thread.fsr,
33 * sizeof(u32),
34 * sizeof(u32));
if (!ret) {
unsigned long val;
val = (1 << 8) | (8 << 16);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&val,
34 * sizeof(u32),
35 * sizeof(u32));
} }
success:
pt_succ_return(regs, 0);
return;
failure:
pt_error_return(regs, EIO);
return;
}
/* #define ALLOW_INIT_TRACING */ if (!ret)
/* #define DEBUG_PTRACE */ ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
35 * sizeof(u32), -1);
#ifdef DEBUG_PTRACE
char *pt_rq [] = {
/* 0 */ "TRACEME", "PEEKTEXT", "PEEKDATA", "PEEKUSR",
/* 4 */ "POKETEXT", "POKEDATA", "POKEUSR", "CONT",
/* 8 */ "KILL", "SINGLESTEP", "SUNATTACH", "SUNDETACH",
/* 12 */ "GETREGS", "SETREGS", "GETFPREGS", "SETFPREGS",
/* 16 */ "READDATA", "WRITEDATA", "READTEXT", "WRITETEXT",
/* 20 */ "GETFPAREGS", "SETFPAREGS", "unknown", "unknown",
/* 24 */ "SYSCALL", ""
};
#endif
/* return ret;
* Called by kernel/ptrace.c when detaching..
*
* Make sure single step bits etc are not set.
*/
void ptrace_disable(struct task_struct *child)
{
/* nothing to do */
} }
asmlinkage void do_ptrace(struct pt_regs *regs) static int fpregs32_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 request = regs->u_regs[UREG_I0]; unsigned long *fpregs = target->thread.float_regs;
unsigned long pid = regs->u_regs[UREG_I1];
unsigned long addr = regs->u_regs[UREG_I2];
unsigned long data = regs->u_regs[UREG_I3];
unsigned long addr2 = regs->u_regs[UREG_I4];
struct task_struct *child;
int ret; int ret;
lock_kernel(); #if 0
#ifdef DEBUG_PTRACE if (target == current)
{ save_and_clear_fpu();
char *s;
if ((request >= 0) && (request <= 24))
s = pt_rq [request];
else
s = "unknown";
if (request == PTRACE_POKEDATA && data == 0x91d02001){
printk ("do_ptrace: breakpoint pid=%d, addr=%08lx addr2=%08lx\n",
pid, addr, addr2);
} else
printk("do_ptrace: rq=%s(%d) pid=%d addr=%08lx data=%08lx addr2=%08lx\n",
s, (int) request, (int) pid, addr, data, addr2);
}
#endif #endif
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
if (request == PTRACE_TRACEME) { fpregs,
ret = ptrace_traceme(); 0, 32 * sizeof(u32));
if (ret < 0) if (!ret)
pt_error_return(regs, -ret); user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
else 32 * sizeof(u32),
pt_succ_return(regs, 0); 33 * sizeof(u32));
goto out; if (!ret && count > 0) {
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&target->thread.fsr,
33 * sizeof(u32),
34 * sizeof(u32));
} }
child = ptrace_get_task_struct(pid); if (!ret)
if (IS_ERR(child)) { ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
ret = PTR_ERR(child); 34 * sizeof(u32), -1);
pt_error_return(regs, -ret); return ret;
goto out; }
}
if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH) static const struct user_regset sparc32_regsets[] = {
|| (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { /* Format is:
if (ptrace_attach(child)) { * G0 --> G7
pt_error_return(regs, EPERM); * O0 --> O7
goto out_tsk; * L0 --> L7
} * I0 --> I7
pt_succ_return(regs, 0); * PSR, PC, nPC, Y, WIM, TBR
goto out_tsk; */
} [REGSET_GENERAL] = {
.core_note_type = NT_PRSTATUS,
.n = 38 * sizeof(u32),
.size = sizeof(u32), .align = sizeof(u32),
.get = genregs32_get, .set = genregs32_set
},
/* Format is:
* F0 --> F31
* empty 32-bit word
* FSR (32--bit word)
* FPU QUEUE COUNT (8-bit char)
* FPU QUEUE ENTRYSIZE (8-bit char)
* FPU ENABLED (8-bit char)
* empty 8-bit char
* FPU QUEUE (64 32-bit ints)
*/
[REGSET_FP] = {
.core_note_type = NT_PRFPREG,
.n = 99 * sizeof(u32),
.size = sizeof(u32), .align = sizeof(u32),
.get = fpregs32_get, .set = fpregs32_set
},
};
ret = ptrace_check_attach(child, request == PTRACE_KILL); static const struct user_regset_view user_sparc32_view = {
if (ret < 0) { .name = "sparc", .e_machine = EM_SPARC,
pt_error_return(regs, -ret); .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
goto out_tsk; };
}
switch(request) { const struct user_regset_view *task_user_regset_view(struct task_struct *task)
case PTRACE_PEEKTEXT: /* read word at location addr. */ {
case PTRACE_PEEKDATA: { return &user_sparc32_view;
unsigned long tmp; }
if (access_process_vm(child, addr,
&tmp, sizeof(tmp), 0) == sizeof(tmp))
pt_os_succ_return(regs, tmp, (long __user *)data);
else
pt_error_return(regs, EIO);
goto out_tsk;
}
case PTRACE_PEEKUSR: long arch_ptrace(struct task_struct *child, long request, long addr, long data)
read_sunos_user(regs, addr, child, (long __user *) data); {
goto out_tsk; unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4];
const struct user_regset_view *view;
case PTRACE_POKEUSR: int ret;
write_sunos_user(regs, addr, child);
goto out_tsk; view = task_user_regset_view(child);
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA: {
if (access_process_vm(child, addr,
&data, sizeof(data), 1) == sizeof(data))
pt_succ_return(regs, 0);
else
pt_error_return(regs, EIO);
goto out_tsk;
}
switch(request) {
case PTRACE_GETREGS: { case PTRACE_GETREGS: {
struct pt_regs __user *pregs = (struct pt_regs __user *) addr; struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
struct pt_regs *cregs = child->thread.kregs;
int rval;
if (!access_ok(VERIFY_WRITE, pregs, sizeof(struct pt_regs))) { ret = copy_regset_to_user(child, view, REGSET_GENERAL,
rval = -EFAULT; 32 * sizeof(u32),
pt_error_return(regs, -rval); 4 * sizeof(u32),
goto out_tsk; &pregs->psr);
} if (!ret)
__put_user(cregs->psr, (&pregs->psr)); copy_regset_to_user(child, view, REGSET_GENERAL,
__put_user(cregs->pc, (&pregs->pc)); 1 * sizeof(u32),
__put_user(cregs->npc, (&pregs->npc)); 15 * sizeof(u32),
__put_user(cregs->y, (&pregs->y)); &pregs->u_regs[0]);
for(rval = 1; rval < 16; rval++) break;
__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]));
pt_succ_return(regs, 0);
#ifdef DEBUG_PTRACE
printk ("PC=%x nPC=%x o7=%x\n", cregs->pc, cregs->npc, cregs->u_regs [15]);
#endif
goto out_tsk;
} }
case PTRACE_SETREGS: { case PTRACE_SETREGS: {
struct pt_regs __user *pregs = (struct pt_regs __user *) addr; struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
struct pt_regs *cregs = child->thread.kregs;
unsigned long psr, pc, npc, y; ret = copy_regset_from_user(child, view, REGSET_GENERAL,
int i; 32 * sizeof(u32),
4 * sizeof(u32),
/* Must be careful, tracing process can only set certain &pregs->psr);
* bits in the psr. if (!ret)
*/ copy_regset_from_user(child, view, REGSET_GENERAL,
if (!access_ok(VERIFY_READ, pregs, sizeof(struct pt_regs))) { 1 * sizeof(u32),
pt_error_return(regs, EFAULT); 15 * sizeof(u32),
goto out_tsk; &pregs->u_regs[0]);
} break;
__get_user(psr, (&pregs->psr));
__get_user(pc, (&pregs->pc));
__get_user(npc, (&pregs->npc));
__get_user(y, (&pregs->y));
psr &= PSR_ICC;
cregs->psr &= ~PSR_ICC;
cregs->psr |= psr;
if (!((pc | npc) & 3)) {
cregs->pc = pc;
cregs->npc =npc;
}
cregs->y = y;
for(i = 1; i < 16; i++)
__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]));
pt_succ_return(regs, 0);
goto out_tsk;
} }
case PTRACE_GETFPREGS: { case PTRACE_GETFPREGS: {
...@@ -417,26 +371,25 @@ asmlinkage void do_ptrace(struct pt_regs *regs) ...@@ -417,26 +371,25 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
} fpq[16]; } fpq[16];
}; };
struct fps __user *fps = (struct fps __user *) addr; struct fps __user *fps = (struct fps __user *) addr;
int i;
if (!access_ok(VERIFY_WRITE, fps, sizeof(struct fps))) { ret = copy_regset_to_user(child, view, REGSET_FP,
i = -EFAULT; 0 * sizeof(u32),
pt_error_return(regs, -i); 32 * sizeof(u32),
goto out_tsk; &fps->regs[0]);
} if (!ret)
for(i = 0; i < 32; i++) ret = copy_regset_to_user(child, view, REGSET_FP,
__put_user(child->thread.float_regs[i], (&fps->regs[i])); 33 * sizeof(u32),
__put_user(child->thread.fsr, (&fps->fsr)); 1 * sizeof(u32),
__put_user(child->thread.fpqdepth, (&fps->fpqd)); &fps->fsr);
__put_user(0, (&fps->flags));
__put_user(0, (&fps->extra)); if (!ret) {
for(i = 0; i < 16; i++) { if (__put_user(0, &fps->fpqd) ||
__put_user(child->thread.fpqueue[i].insn_addr, __put_user(0, &fps->flags) ||
(&fps->fpq[i].insnaddr)); __put_user(0, &fps->extra) ||
__put_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn)); clear_user(fps->fpq, sizeof(fps->fpq)))
ret = -EFAULT;
} }
pt_succ_return(regs, 0); break;
goto out_tsk;
} }
case PTRACE_SETFPREGS: { case PTRACE_SETFPREGS: {
...@@ -452,137 +405,55 @@ asmlinkage void do_ptrace(struct pt_regs *regs) ...@@ -452,137 +405,55 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
} fpq[16]; } fpq[16];
}; };
struct fps __user *fps = (struct fps __user *) addr; struct fps __user *fps = (struct fps __user *) addr;
int i;
if (!access_ok(VERIFY_READ, fps, sizeof(struct fps))) { ret = copy_regset_from_user(child, view, REGSET_FP,
i = -EFAULT; 0 * sizeof(u32),
pt_error_return(regs, -i); 32 * sizeof(u32),
goto out_tsk; &fps->regs[0]);
} if (!ret)
copy_from_user(&child->thread.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned long))); ret = copy_regset_from_user(child, view, REGSET_FP,
__get_user(child->thread.fsr, (&fps->fsr)); 33 * sizeof(u32),
__get_user(child->thread.fpqdepth, (&fps->fpqd)); 1 * sizeof(u32),
for(i = 0; i < 16; i++) { &fps->fsr);
__get_user(child->thread.fpqueue[i].insn_addr, break;
(&fps->fpq[i].insnaddr));
__get_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn));
}
pt_succ_return(regs, 0);
goto out_tsk;
} }
case PTRACE_READTEXT: case PTRACE_READTEXT:
case PTRACE_READDATA: { case PTRACE_READDATA:
int res = ptrace_readdata(child, addr, ret = ptrace_readdata(child, addr,
(void __user *) addr2, data); (void __user *) addr2, data);
if (res == data) { if (ret == data)
pt_succ_return(regs, 0); ret = 0;
goto out_tsk; else if (ret >= 0)
} ret = -EIO;
/* Partial read is an IO failure */ break;
if (res >= 0)
res = -EIO;
pt_error_return(regs, -res);
goto out_tsk;
}
case PTRACE_WRITETEXT: case PTRACE_WRITETEXT:
case PTRACE_WRITEDATA: { case PTRACE_WRITEDATA:
int res = ptrace_writedata(child, (void __user *) addr2, ret = ptrace_writedata(child, (void __user *) addr2,
addr, data); addr, data);
if (res == data) { if (ret == data)
pt_succ_return(regs, 0); ret = 0;
goto out_tsk; else if (ret >= 0)
} ret = -EIO;
/* Partial write is an IO failure */ break;
if (res >= 0)
res = -EIO;
pt_error_return(regs, -res);
goto out_tsk;
}
case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
addr = 1;
case PTRACE_CONT: { /* restart after signal. */
if (!valid_signal(data)) {
pt_error_return(regs, EIO);
goto out_tsk;
}
if (request == PTRACE_SYSCALL)
set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
else
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
child->exit_code = data;
#ifdef DEBUG_PTRACE
printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n",
child->comm, child->pid, child->exit_code,
child->thread.kregs->pc,
child->thread.kregs->npc);
#endif
wake_up_process(child);
pt_succ_return(regs, 0);
goto out_tsk;
}
/*
* 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: {
if (child->exit_state == EXIT_ZOMBIE) { /* already dead */
pt_succ_return(regs, 0);
goto out_tsk;
}
wake_up_process(child);
child->exit_code = SIGKILL;
pt_succ_return(regs, 0);
goto out_tsk;
}
case PTRACE_SUNDETACH: { /* detach a process that was attached. */ default:
int err = ptrace_detach(child, data); ret = ptrace_request(child, request, addr, data);
if (err) { break;
pt_error_return(regs, EIO);
goto out_tsk;
}
pt_succ_return(regs, 0);
goto out_tsk;
} }
/* PTRACE_DUMPCORE unsupported... */ return ret;
default: {
int err = ptrace_request(child, request, addr, data);
if (err)
pt_error_return(regs, -err);
else
pt_succ_return(regs, 0);
goto out_tsk;
}
}
out_tsk:
if (child)
put_task_struct(child);
out:
unlock_kernel();
} }
asmlinkage void syscall_trace(void) asmlinkage void syscall_trace(void)
{ {
#ifdef DEBUG_PTRACE
printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
#endif
if (!test_thread_flag(TIF_SYSCALL_TRACE)) if (!test_thread_flag(TIF_SYSCALL_TRACE))
return; return;
if (!(current->ptrace & PT_PTRACED)) if (!(current->ptrace & PT_PTRACED))
return; return;
current->thread.flags ^= MAGIC_CONSTANT;
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
? 0x80 : 0)); ? 0x80 : 0));
/* /*
...@@ -590,10 +461,6 @@ asmlinkage void syscall_trace(void) ...@@ -590,10 +461,6 @@ asmlinkage void syscall_trace(void)
* for normal use. strace only continues with a signal if the * for normal use. strace only continues with a signal if the
* stopping signal is not SIGTRAP. -brl * stopping signal is not SIGTRAP. -brl
*/ */
#ifdef DEBUG_PTRACE
printk("%s [%d]: syscall_trace exit= %x\n", current->comm,
current->pid, current->exit_code);
#endif
if (current->exit_code) { if (current->exit_code) {
send_sig (current->exit_code, current, 1); send_sig (current->exit_code, current, 1);
current->exit_code = 0; current->exit_code = 0;
......
/* /*
* binfmt_elf32.c: Support 32-bit Sparc ELF binaries on Ultra. * binfmt_elf32.c: Support 32-bit Sparc ELF binaries on Ultra.
* *
* Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@davemloft.net) * Copyright (C) 1995, 1996, 1997, 1998, 2008 David S. Miller (davem@davemloft.net)
* Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz) * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz)
*/ */
...@@ -9,13 +9,6 @@ ...@@ -9,13 +9,6 @@
#define ELF_CLASS ELFCLASS32 #define ELF_CLASS ELFCLASS32
#define ELF_DATA ELFDATA2MSB; #define ELF_DATA ELFDATA2MSB;
/* For the most part we present code dumps in the format
* Solaris does.
*/
typedef unsigned int elf_greg_t;
#define ELF_NGREG 38
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
/* Format is: /* Format is:
* G0 --> G7 * G0 --> G7
* O0 --> O7 * O0 --> O7
...@@ -23,25 +16,9 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG]; ...@@ -23,25 +16,9 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
* I0 --> I7 * I0 --> I7
* PSR, PC, nPC, Y, WIM, TBR * PSR, PC, nPC, Y, WIM, TBR
*/ */
#include <asm/psrcompat.h> typedef unsigned int elf_greg_t;
#define ELF_CORE_COPY_REGS(__elf_regs, __pt_regs) \ #define ELF_NGREG 38
do { unsigned int *dest = &(__elf_regs[0]); \ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
struct pt_regs *src = (__pt_regs); \
unsigned int __user *sp; \
int i; \
for(i = 0; i < 16; i++) \
dest[i] = (unsigned int) src->u_regs[i];\
/* Don't try this at home kids... */ \
sp = (unsigned int __user *) (src->u_regs[14] & \
0x00000000fffffffc); \
for(i = 0; i < 16; i++) \
__get_user(dest[i+16], &sp[i]); \
dest[32] = tstate_to_psr(src->tstate); \
dest[33] = (unsigned int) src->tpc; \
dest[34] = (unsigned int) src->tnpc; \
dest[35] = src->y; \
dest[36] = dest[37] = 0; /* XXX */ \
} while(0);
typedef struct { typedef struct {
union { union {
......
...@@ -1477,10 +1477,6 @@ sys32_rt_sigreturn: ...@@ -1477,10 +1477,6 @@ sys32_rt_sigreturn:
add %o7, 1f-.-4, %o7 add %o7, 1f-.-4, %o7
nop nop
#endif #endif
sys_ptrace: add %sp, PTREGS_OFF, %o0
call do_ptrace
add %o7, 1f-.-4, %o7
nop
.align 32 .align 32
1: ldx [%curptr + TI_FLAGS], %l5 1: ldx [%curptr + TI_FLAGS], %l5
andcc %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0 andcc %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0
......
...@@ -632,11 +632,36 @@ tlb_fixup_done: ...@@ -632,11 +632,36 @@ tlb_fixup_done:
/* Not reached... */ /* Not reached... */
1: 1:
/* If we boot on a non-zero cpu, all of the per-cpu
* variable references we make before setting up the
* per-cpu areas will use a bogus offset. Put a
* compensating factor into __per_cpu_base to handle
* this cleanly.
*
* What the per-cpu code calculates is:
*
* __per_cpu_base + (cpu << __per_cpu_shift)
*
* These two variables are zero initially, so to
* make it all cancel out to zero we need to put
* "0 - (cpu << 0)" into __per_cpu_base so that the
* above formula evaluates to zero.
*
* We cannot even perform a printk() until this stuff
* is setup as that calls cpu_clock() which uses
* per-cpu variables.
*/
sub %g0, %o0, %o1
sethi %hi(__per_cpu_base), %o2
stx %o1, [%o2 + %lo(__per_cpu_base)]
#else #else
mov 0, %o0 mov 0, %o0
#endif #endif
sth %o0, [%g6 + TI_CPU] sth %o0, [%g6 + TI_CPU]
call prom_init_report
nop
/* Off we go.... */ /* Off we go.... */
call start_kernel call start_kernel
nop nop
......
/* ptrace.c: Sparc process tracing support. /* ptrace.c: Sparc process tracing support.
* *
* Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net)
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
* *
* Based upon code written by Ross Biro, Linus Torvalds, Bob Manson, * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
...@@ -22,6 +22,9 @@ ...@@ -22,6 +22,9 @@
#include <linux/seccomp.h> #include <linux/seccomp.h>
#include <linux/audit.h> #include <linux/audit.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/regset.h>
#include <linux/compat.h>
#include <linux/elf.h>
#include <asm/asi.h> #include <asm/asi.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
...@@ -33,70 +36,7 @@ ...@@ -33,70 +36,7 @@
#include <asm/page.h> #include <asm/page.h>
#include <asm/cpudata.h> #include <asm/cpudata.h>
/* Returning from ptrace is a bit tricky because the syscall return
* low level code assumes any value returned which is negative and
* is a valid errno will mean setting the condition codes to indicate
* an error return. This doesn't work, so we have this hook.
*/
static inline void pt_error_return(struct pt_regs *regs, unsigned long error)
{
regs->u_regs[UREG_I0] = error;
regs->tstate |= (TSTATE_ICARRY | TSTATE_XCARRY);
regs->tpc = regs->tnpc;
regs->tnpc += 4;
}
static inline void pt_succ_return(struct pt_regs *regs, unsigned long value)
{
regs->u_regs[UREG_I0] = value;
regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY);
regs->tpc = regs->tnpc;
regs->tnpc += 4;
}
static inline void
pt_succ_return_linux(struct pt_regs *regs, unsigned long value, void __user *addr)
{
if (test_thread_flag(TIF_32BIT)) {
if (put_user(value, (unsigned int __user *) addr)) {
pt_error_return(regs, EFAULT);
return;
}
} else {
if (put_user(value, (long __user *) addr)) {
pt_error_return(regs, EFAULT);
return;
}
}
regs->u_regs[UREG_I0] = 0;
regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY);
regs->tpc = regs->tnpc;
regs->tnpc += 4;
}
static void
pt_os_succ_return (struct pt_regs *regs, unsigned long val, void __user *addr)
{
if (current->personality == PER_SUNOS)
pt_succ_return (regs, val);
else
pt_succ_return_linux (regs, val, addr);
}
/* #define ALLOW_INIT_TRACING */ /* #define ALLOW_INIT_TRACING */
/* #define DEBUG_PTRACE */
#ifdef DEBUG_PTRACE
char *pt_rq [] = {
/* 0 */ "TRACEME", "PEEKTEXT", "PEEKDATA", "PEEKUSR",
/* 4 */ "POKETEXT", "POKEDATA", "POKEUSR", "CONT",
/* 8 */ "KILL", "SINGLESTEP", "SUNATTACH", "SUNDETACH",
/* 12 */ "GETREGS", "SETREGS", "GETFPREGS", "SETFPREGS",
/* 16 */ "READDATA", "WRITEDATA", "READTEXT", "WRITETEXT",
/* 20 */ "GETFPAREGS", "SETFPAREGS", "unknown", "unknown",
/* 24 */ "SYSCALL", ""
};
#endif
/* /*
* Called by kernel/ptrace.c when detaching.. * Called by kernel/ptrace.c when detaching..
...@@ -167,267 +107,709 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, ...@@ -167,267 +107,709 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
} }
} }
asmlinkage void do_ptrace(struct pt_regs *regs) enum sparc_regset {
REGSET_GENERAL,
REGSET_FP,
};
static int genregs64_get(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{ {
int request = regs->u_regs[UREG_I0]; const struct pt_regs *regs = task_pt_regs(target);
pid_t pid = regs->u_regs[UREG_I1];
unsigned long addr = regs->u_regs[UREG_I2];
unsigned long data = regs->u_regs[UREG_I3];
unsigned long addr2 = regs->u_regs[UREG_I4];
struct task_struct *child;
int ret; int ret;
if (test_thread_flag(TIF_32BIT)) { if (target == current)
addr &= 0xffffffffUL; flushw_user();
data &= 0xffffffffUL;
addr2 &= 0xffffffffUL; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
regs->u_regs,
0, 16 * sizeof(u64));
if (!ret) {
unsigned long __user *reg_window = (unsigned long __user *)
(regs->u_regs[UREG_I6] + STACK_BIAS);
unsigned long window[16];
if (copy_from_user(window, reg_window, sizeof(window)))
return -EFAULT;
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
window,
16 * sizeof(u64),
32 * sizeof(u64));
} }
lock_kernel();
#ifdef DEBUG_PTRACE
{
char *s;
if ((request >= 0) && (request <= 24)) if (!ret) {
s = pt_rq [request]; /* TSTATE, TPC, TNPC */
else ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
s = "unknown"; &regs->tstate,
32 * sizeof(u64),
35 * sizeof(u64));
}
if (!ret) {
unsigned long y = regs->y;
if (request == PTRACE_POKEDATA && data == 0x91d02001){ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
printk ("do_ptrace: breakpoint pid=%d, addr=%016lx addr2=%016lx\n", &y,
pid, addr, addr2); 35 * sizeof(u64),
} else 36 * sizeof(u64));
printk("do_ptrace: rq=%s(%d) pid=%d addr=%016lx data=%016lx addr2=%016lx\n",
s, request, pid, addr, data, addr2);
} }
#endif
if (request == PTRACE_TRACEME) { if (!ret)
ret = ptrace_traceme(); ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
if (ret < 0) 36 * sizeof(u64), -1);
pt_error_return(regs, -ret);
return ret;
}
static int genregs64_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);
int ret;
if (target == current)
flushw_user();
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
regs->u_regs,
0, 16 * sizeof(u64));
if (!ret && count > 0) {
unsigned long __user *reg_window = (unsigned long __user *)
(regs->u_regs[UREG_I6] + STACK_BIAS);
unsigned long window[16];
if (copy_from_user(window, reg_window, sizeof(window)))
return -EFAULT;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
window,
16 * sizeof(u64),
32 * sizeof(u64));
if (!ret &&
copy_to_user(reg_window, window, sizeof(window)))
return -EFAULT;
}
if (!ret && count > 0) {
unsigned long tstate;
/* TSTATE */
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&tstate,
32 * sizeof(u64),
33 * sizeof(u64));
if (!ret) {
/* Only the condition codes can be modified
* in the %tstate register.
*/
tstate &= (TSTATE_ICC | TSTATE_XCC);
regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
regs->tstate |= tstate;
}
}
if (!ret) {
/* TPC, TNPC */
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&regs->tpc,
33 * sizeof(u64),
35 * sizeof(u64));
}
if (!ret) {
unsigned long y;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&y,
35 * sizeof(u64),
36 * sizeof(u64));
if (!ret)
regs->y = y;
}
if (!ret)
ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
36 * sizeof(u64), -1);
return ret;
}
static int fpregs64_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, fsr, gsr;
int ret;
if (target == current)
save_and_clear_fpu();
fprs = task_thread_info(target)->fpsaved[0];
if (fprs & FPRS_DL)
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
fpregs,
0, 16 * sizeof(u64));
else
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
0,
16 * sizeof(u64));
if (!ret) {
if (fprs & FPRS_DU)
ret = user_regset_copyout(&pos, &count,
&kbuf, &ubuf,
fpregs + 16,
16 * sizeof(u64),
32 * sizeof(u64));
else else
pt_succ_return(regs, 0); ret = user_regset_copyout_zero(&pos, &count,
goto out; &kbuf, &ubuf,
16 * sizeof(u64),
32 * sizeof(u64));
} }
child = ptrace_get_task_struct(pid); if (fprs & FPRS_FEF) {
if (IS_ERR(child)) { fsr = task_thread_info(target)->xfsr[0];
ret = PTR_ERR(child); gsr = task_thread_info(target)->gsr[0];
pt_error_return(regs, -ret); } else {
goto out; fsr = gsr = 0;
} }
if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH) if (!ret)
|| (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
if (ptrace_attach(child)) { &fsr,
pt_error_return(regs, EPERM); 32 * sizeof(u64),
goto out_tsk; 33 * sizeof(u64));
if (!ret)
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&gsr,
33 * sizeof(u64),
34 * sizeof(u64));
if (!ret)
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&fprs,
34 * sizeof(u64),
35 * sizeof(u64));
if (!ret)
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
35 * sizeof(u64), -1);
return ret;
}
static int fpregs64_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();
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
fpregs,
0, 32 * sizeof(u64));
if (!ret)
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
task_thread_info(target)->xfsr,
32 * sizeof(u64),
33 * sizeof(u64));
if (!ret)
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
task_thread_info(target)->gsr,
33 * sizeof(u64),
34 * sizeof(u64));
fprs = task_thread_info(target)->fpsaved[0];
if (!ret && count > 0) {
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&fprs,
34 * sizeof(u64),
35 * sizeof(u64));
}
fprs |= (FPRS_FEF | FPRS_DL | FPRS_DU);
task_thread_info(target)->fpsaved[0] = fprs;
if (!ret)
ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
35 * sizeof(u64), -1);
return ret;
}
static const struct user_regset sparc64_regsets[] = {
/* Format is:
* G0 --> G7
* O0 --> O7
* L0 --> L7
* I0 --> I7
* TSTATE, TPC, TNPC, Y
*/
[REGSET_GENERAL] = {
.core_note_type = NT_PRSTATUS,
.n = 36 * sizeof(u64),
.size = sizeof(u64), .align = sizeof(u64),
.get = genregs64_get, .set = genregs64_set
},
/* Format is:
* F0 --> F63
* FSR
* GSR
* FPRS
*/
[REGSET_FP] = {
.core_note_type = NT_PRFPREG,
.n = 35 * sizeof(u64),
.size = sizeof(u64), .align = sizeof(u64),
.get = fpregs64_get, .set = fpregs64_set
},
};
static const struct user_regset_view user_sparc64_view = {
.name = "sparc64", .e_machine = EM_SPARCV9,
.regsets = sparc64_regsets, .n = ARRAY_SIZE(sparc64_regsets)
};
static int genregs32_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);
compat_ulong_t __user *reg_window;
compat_ulong_t *k = kbuf;
compat_ulong_t __user *u = ubuf;
compat_ulong_t reg;
if (target == current)
flushw_user();
pos /= sizeof(reg);
count /= sizeof(reg);
if (kbuf) {
for (; count > 0 && pos < 16; count--)
*k++ = regs->u_regs[pos++];
reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
for (; count > 0 && pos < 32; count--) {
if (get_user(*k++, &reg_window[pos++]))
return -EFAULT;
}
} else {
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];
for (; count > 0 && pos < 32; count--) {
if (get_user(reg, &reg_window[pos++]) ||
put_user(reg, u++))
return -EFAULT;
} }
pt_succ_return(regs, 0);
goto out_tsk;
} }
while (count > 0) {
switch (pos) {
case 32: /* PSR */
reg = tstate_to_psr(regs->tstate);
break;
case 33: /* PC */
reg = regs->tpc;
break;
case 34: /* NPC */
reg = regs->tnpc;
break;
case 35: /* Y */
reg = regs->y;
break;
case 36: /* WIM */
case 37: /* TBR */
reg = 0;
break;
default:
goto finish;
}
ret = ptrace_check_attach(child, request == PTRACE_KILL); if (kbuf)
if (ret < 0) { *k++ = reg;
pt_error_return(regs, -ret); else if (put_user(reg, u++))
goto out_tsk; return -EFAULT;
pos++;
count--;
} }
finish:
pos *= sizeof(reg);
count *= sizeof(reg);
return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
38 * sizeof(reg), -1);
}
if (!(test_thread_flag(TIF_32BIT)) && static int genregs32_set(struct task_struct *target,
((request == PTRACE_READDATA64) || const struct user_regset *regset,
(request == PTRACE_WRITEDATA64) || unsigned int pos, unsigned int count,
(request == PTRACE_READTEXT64) || const void *kbuf, const void __user *ubuf)
(request == PTRACE_WRITETEXT64) || {
(request == PTRACE_PEEKTEXT64) || struct pt_regs *regs = task_pt_regs(target);
(request == PTRACE_POKETEXT64) || compat_ulong_t __user *reg_window;
(request == PTRACE_PEEKDATA64) || const compat_ulong_t *k = kbuf;
(request == PTRACE_POKEDATA64))) { const compat_ulong_t __user *u = ubuf;
addr = regs->u_regs[UREG_G2]; compat_ulong_t reg;
addr2 = regs->u_regs[UREG_G3];
request -= 30; /* wheee... */ if (target == current)
flushw_user();
pos /= sizeof(reg);
count /= sizeof(reg);
if (kbuf) {
for (; count > 0 && pos < 16; count--)
regs->u_regs[pos++] = *k++;
reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
for (; count > 0 && pos < 32; count--) {
if (put_user(*k++, &reg_window[pos++]))
return -EFAULT;
}
} else {
for (; count > 0 && pos < 16; count--) {
if (get_user(reg, u++))
return -EFAULT;
regs->u_regs[pos++] = reg;
}
reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
for (; count > 0 && pos < 32; count--) {
if (get_user(reg, u++) ||
put_user(reg, &reg_window[pos++]))
return -EFAULT;
}
} }
while (count > 0) {
unsigned long tstate;
if (kbuf)
reg = *k++;
else if (get_user(reg, u++))
return -EFAULT;
switch (pos) {
case 32: /* PSR */
tstate = regs->tstate;
tstate &= ~(TSTATE_ICC | TSTATE_XCC);
tstate |= psr_to_tstate_icc(reg);
regs->tstate = tstate;
break;
case 33: /* PC */
regs->tpc = reg;
break;
case 34: /* NPC */
regs->tnpc = reg;
break;
case 35: /* Y */
regs->y = reg;
break;
case 36: /* WIM */
case 37: /* TBR */
break;
default:
goto finish;
}
pos++;
count--;
}
finish:
pos *= sizeof(reg);
count *= sizeof(reg);
return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
38 * sizeof(reg), -1);
}
static int fpregs32_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;
compat_ulong_t enabled;
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];
enabled = 1;
} else {
fsr = 0;
enabled = 0;
}
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
fpregs,
0, 32 * sizeof(u32));
if (!ret)
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
32 * sizeof(u32),
33 * sizeof(u32));
if (!ret)
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&fsr,
33 * sizeof(u32),
34 * sizeof(u32));
if (!ret) {
compat_ulong_t val;
val = (enabled << 8) | (8 << 16);
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&val,
34 * sizeof(u32),
35 * sizeof(u32));
}
if (!ret)
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
35 * sizeof(u32), -1);
return ret;
}
static int fpregs32_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)
user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
32 * sizeof(u32),
33 * sizeof(u32));
if (!ret && count > 0) {
compat_ulong_t fsr;
unsigned long val;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&fsr,
33 * sizeof(u32),
34 * 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;
if (!ret)
ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
34 * sizeof(u32), -1);
return ret;
}
static const struct user_regset sparc32_regsets[] = {
/* Format is:
* G0 --> G7
* O0 --> O7
* L0 --> L7
* I0 --> I7
* PSR, PC, nPC, Y, WIM, TBR
*/
[REGSET_GENERAL] = {
.core_note_type = NT_PRSTATUS,
.n = 38 * sizeof(u32),
.size = sizeof(u32), .align = sizeof(u32),
.get = genregs32_get, .set = genregs32_set
},
/* Format is:
* F0 --> F31
* empty 32-bit word
* FSR (32--bit word)
* FPU QUEUE COUNT (8-bit char)
* FPU QUEUE ENTRYSIZE (8-bit char)
* FPU ENABLED (8-bit char)
* empty 8-bit char
* FPU QUEUE (64 32-bit ints)
*/
[REGSET_FP] = {
.core_note_type = NT_PRFPREG,
.n = 99 * sizeof(u32),
.size = sizeof(u32), .align = sizeof(u32),
.get = fpregs32_get, .set = fpregs32_set
},
};
static const struct user_regset_view user_sparc32_view = {
.name = "sparc", .e_machine = EM_SPARC,
.regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
};
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
{
if (test_tsk_thread_flag(task, TIF_32BIT))
return &user_sparc32_view;
return &user_sparc64_view;
}
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
long addr2 = task_pt_regs(current)->u_regs[UREG_I4];
const struct user_regset_view *view;
int ret;
if (test_thread_flag(TIF_32BIT))
addr2 &= 0xffffffffUL;
view = task_user_regset_view(child);
switch(request) { switch(request) {
case PTRACE_PEEKUSR: case PTRACE_PEEKUSR:
if (addr != 0) ret = (addr != 0) ? -EIO : 0;
pt_error_return(regs, EIO); break;
else
pt_succ_return(regs, 0);
goto out_tsk;
case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKTEXT: /* read word at location addr. */
case PTRACE_PEEKDATA: { case PTRACE_PEEKDATA: {
unsigned long tmp64; unsigned long tmp64;
unsigned int tmp32; unsigned int tmp32;
int res, copied; int copied;
res = -EIO; ret = -EIO;
if (test_thread_flag(TIF_32BIT)) { if (test_thread_flag(TIF_32BIT)) {
copied = access_process_vm(child, addr, copied = access_process_vm(child, addr,
&tmp32, sizeof(tmp32), 0); &tmp32, sizeof(tmp32), 0);
tmp64 = (unsigned long) tmp32;
if (copied == sizeof(tmp32)) if (copied == sizeof(tmp32))
res = 0; ret = put_user(tmp32,
(unsigned int __user *) data);
} else { } else {
copied = access_process_vm(child, addr, copied = access_process_vm(child, addr,
&tmp64, sizeof(tmp64), 0); &tmp64, sizeof(tmp64), 0);
if (copied == sizeof(tmp64)) if (copied == sizeof(tmp64))
res = 0; ret = put_user(tmp64,
(unsigned long __user *) data);
} }
if (res < 0) break;
pt_error_return(regs, -res);
else
pt_os_succ_return(regs, tmp64, (void __user *) data);
goto out_tsk;
} }
case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA: { case PTRACE_POKEDATA: {
unsigned long tmp64; unsigned long tmp64;
unsigned int tmp32; unsigned int tmp32;
int copied, res = -EIO; int copied;
ret = -EIO;
if (test_thread_flag(TIF_32BIT)) { if (test_thread_flag(TIF_32BIT)) {
tmp32 = data; tmp32 = data;
copied = access_process_vm(child, addr, copied = access_process_vm(child, addr,
&tmp32, sizeof(tmp32), 1); &tmp32, sizeof(tmp32), 1);
if (copied == sizeof(tmp32)) if (copied == sizeof(tmp32))
res = 0; ret = 0;
} else { } else {
tmp64 = data; tmp64 = data;
copied = access_process_vm(child, addr, copied = access_process_vm(child, addr,
&tmp64, sizeof(tmp64), 1); &tmp64, sizeof(tmp64), 1);
if (copied == sizeof(tmp64)) if (copied == sizeof(tmp64))
res = 0; ret = 0;
} }
if (res < 0) break;
pt_error_return(regs, -res);
else
pt_succ_return(regs, res);
goto out_tsk;
} }
case PTRACE_GETREGS: { case PTRACE_GETREGS: {
struct pt_regs32 __user *pregs = struct pt_regs32 __user *pregs =
(struct pt_regs32 __user *) addr; (struct pt_regs32 __user *) addr;
struct pt_regs *cregs = task_pt_regs(child);
int rval; ret = copy_regset_to_user(child, view, REGSET_GENERAL,
32 * sizeof(u32),
if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) || 4 * sizeof(u32),
__put_user(cregs->tpc, (&pregs->pc)) || &pregs->psr);
__put_user(cregs->tnpc, (&pregs->npc)) || if (!ret)
__put_user(cregs->y, (&pregs->y))) { ret = copy_regset_to_user(child, view, REGSET_GENERAL,
pt_error_return(regs, EFAULT); 1 * sizeof(u32),
goto out_tsk; 15 * sizeof(u32),
} &pregs->u_regs[0]);
for (rval = 1; rval < 16; rval++) break;
if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
pt_error_return(regs, EFAULT);
goto out_tsk;
}
pt_succ_return(regs, 0);
#ifdef DEBUG_PTRACE
printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
#endif
goto out_tsk;
} }
case PTRACE_GETREGS64: { case PTRACE_GETREGS64: {
struct pt_regs __user *pregs = (struct pt_regs __user *) addr; struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
struct pt_regs *cregs = task_pt_regs(child);
unsigned long tpc = cregs->tpc; ret = copy_regset_to_user(child, view, REGSET_GENERAL,
int rval; 1 * sizeof(u64),
15 * sizeof(u64),
if ((task_thread_info(child)->flags & _TIF_32BIT) != 0) &pregs->u_regs[0]);
tpc &= 0xffffffff; if (!ret) {
if (__put_user(cregs->tstate, (&pregs->tstate)) || /* XXX doesn't handle 'y' register correctly XXX */
__put_user(tpc, (&pregs->tpc)) || ret = copy_regset_to_user(child, view, REGSET_GENERAL,
__put_user(cregs->tnpc, (&pregs->tnpc)) || 32 * sizeof(u64),
__put_user(cregs->y, (&pregs->y))) { 4 * sizeof(u64),
pt_error_return(regs, EFAULT); &pregs->tstate);
goto out_tsk;
} }
for (rval = 1; rval < 16; rval++) break;
if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
pt_error_return(regs, EFAULT);
goto out_tsk;
}
pt_succ_return(regs, 0);
#ifdef DEBUG_PTRACE
printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
#endif
goto out_tsk;
} }
case PTRACE_SETREGS: { case PTRACE_SETREGS: {
struct pt_regs32 __user *pregs = struct pt_regs32 __user *pregs =
(struct pt_regs32 __user *) addr; (struct pt_regs32 __user *) addr;
struct pt_regs *cregs = task_pt_regs(child);
unsigned int psr, pc, npc, y; ret = copy_regset_from_user(child, view, REGSET_GENERAL,
int i; 32 * sizeof(u32),
4 * sizeof(u32),
/* Must be careful, tracing process can only set certain &pregs->psr);
* bits in the psr. if (!ret)
*/ ret = copy_regset_from_user(child, view, REGSET_GENERAL,
if (__get_user(psr, (&pregs->psr)) || 1 * sizeof(u32),
__get_user(pc, (&pregs->pc)) || 15 * sizeof(u32),
__get_user(npc, (&pregs->npc)) || &pregs->u_regs[0]);
__get_user(y, (&pregs->y))) { break;
pt_error_return(regs, EFAULT);
goto out_tsk;
}
cregs->tstate &= ~(TSTATE_ICC);
cregs->tstate |= psr_to_tstate_icc(psr);
if (!((pc | npc) & 3)) {
cregs->tpc = pc;
cregs->tnpc = npc;
}
cregs->y = y;
for (i = 1; i < 16; i++) {
if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
pt_error_return(regs, EFAULT);
goto out_tsk;
}
}
pt_succ_return(regs, 0);
goto out_tsk;
} }
case PTRACE_SETREGS64: { case PTRACE_SETREGS64: {
struct pt_regs __user *pregs = (struct pt_regs __user *) addr; struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
struct pt_regs *cregs = task_pt_regs(child);
unsigned long tstate, tpc, tnpc, y; ret = copy_regset_from_user(child, view, REGSET_GENERAL,
int i; 1 * sizeof(u64),
15 * sizeof(u64),
/* Must be careful, tracing process can only set certain &pregs->u_regs[0]);
* bits in the psr. if (!ret) {
*/ /* XXX doesn't handle 'y' register correctly XXX */
if (__get_user(tstate, (&pregs->tstate)) || ret = copy_regset_from_user(child, view, REGSET_GENERAL,
__get_user(tpc, (&pregs->tpc)) || 32 * sizeof(u64),
__get_user(tnpc, (&pregs->tnpc)) || 4 * sizeof(u64),
__get_user(y, (&pregs->y))) { &pregs->tstate);
pt_error_return(regs, EFAULT);
goto out_tsk;
}
if ((task_thread_info(child)->flags & _TIF_32BIT) != 0) {
tpc &= 0xffffffff;
tnpc &= 0xffffffff;
}
tstate &= (TSTATE_ICC | TSTATE_XCC);
cregs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
cregs->tstate |= tstate;
if (!((tpc | tnpc) & 3)) {
cregs->tpc = tpc;
cregs->tnpc = tnpc;
}
cregs->y = y;
for (i = 1; i < 16; i++) {
if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
pt_error_return(regs, EFAULT);
goto out_tsk;
}
} }
pt_succ_return(regs, 0); break;
goto out_tsk;
} }
case PTRACE_GETFPREGS: { case PTRACE_GETFPREGS: {
...@@ -443,20 +825,24 @@ asmlinkage void do_ptrace(struct pt_regs *regs) ...@@ -443,20 +825,24 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
} fpq[16]; } fpq[16];
}; };
struct fps __user *fps = (struct fps __user *) addr; struct fps __user *fps = (struct fps __user *) addr;
unsigned long *fpregs = task_thread_info(child)->fpregs;
ret = copy_regset_to_user(child, view, REGSET_FP,
if (copy_to_user(&fps->regs[0], fpregs, 0 * sizeof(u32),
(32 * sizeof(unsigned int))) || 32 * sizeof(u32),
__put_user(task_thread_info(child)->xfsr[0], (&fps->fsr)) || &fps->regs[0]);
__put_user(0, (&fps->fpqd)) || if (!ret)
__put_user(0, (&fps->flags)) || ret = copy_regset_to_user(child, view, REGSET_FP,
__put_user(0, (&fps->extra)) || 33 * sizeof(u32),
clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) { 1 * sizeof(u32),
pt_error_return(regs, EFAULT); &fps->fsr);
goto out_tsk; 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;
} }
pt_succ_return(regs, 0); break;
goto out_tsk;
} }
case PTRACE_GETFPREGS64: { case PTRACE_GETFPREGS64: {
...@@ -465,16 +851,12 @@ asmlinkage void do_ptrace(struct pt_regs *regs) ...@@ -465,16 +851,12 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
unsigned long fsr; unsigned long fsr;
}; };
struct fps __user *fps = (struct fps __user *) addr; struct fps __user *fps = (struct fps __user *) addr;
unsigned long *fpregs = task_thread_info(child)->fpregs;
if (copy_to_user(&fps->regs[0], fpregs, ret = copy_regset_to_user(child, view, REGSET_FP,
(64 * sizeof(unsigned int))) || 0 * sizeof(u64),
__put_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) { 33 * sizeof(u64),
pt_error_return(regs, EFAULT); fps);
goto out_tsk; break;
}
pt_succ_return(regs, 0);
goto out_tsk;
} }
case PTRACE_SETFPREGS: { case PTRACE_SETFPREGS: {
...@@ -490,22 +872,17 @@ asmlinkage void do_ptrace(struct pt_regs *regs) ...@@ -490,22 +872,17 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
} fpq[16]; } fpq[16];
}; };
struct fps __user *fps = (struct fps __user *) addr; struct fps __user *fps = (struct fps __user *) addr;
unsigned long *fpregs = task_thread_info(child)->fpregs;
unsigned fsr; ret = copy_regset_from_user(child, view, REGSET_FP,
0 * sizeof(u32),
if (copy_from_user(fpregs, &fps->regs[0], 32 * sizeof(u32),
(32 * sizeof(unsigned int))) || &fps->regs[0]);
__get_user(fsr, (&fps->fsr))) { if (!ret)
pt_error_return(regs, EFAULT); ret = copy_regset_from_user(child, view, REGSET_FP,
goto out_tsk; 33 * sizeof(u32),
} 1 * sizeof(u32),
task_thread_info(child)->xfsr[0] &= 0xffffffff00000000UL; &fps->fsr);
task_thread_info(child)->xfsr[0] |= fsr; break;
if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF))
task_thread_info(child)->gsr[0] = 0;
task_thread_info(child)->fpsaved[0] |= (FPRS_FEF | FPRS_DL);
pt_succ_return(regs, 0);
goto out_tsk;
} }
case PTRACE_SETFPREGS64: { case PTRACE_SETFPREGS64: {
...@@ -514,134 +891,50 @@ asmlinkage void do_ptrace(struct pt_regs *regs) ...@@ -514,134 +891,50 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
unsigned long fsr; unsigned long fsr;
}; };
struct fps __user *fps = (struct fps __user *) addr; struct fps __user *fps = (struct fps __user *) addr;
unsigned long *fpregs = task_thread_info(child)->fpregs;
if (copy_from_user(fpregs, &fps->regs[0], ret = copy_regset_to_user(child, view, REGSET_FP,
(64 * sizeof(unsigned int))) || 0 * sizeof(u64),
__get_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) { 33 * sizeof(u64),
pt_error_return(regs, EFAULT); fps);
goto out_tsk; break;
}
if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF))
task_thread_info(child)->gsr[0] = 0;
task_thread_info(child)->fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU);
pt_succ_return(regs, 0);
goto out_tsk;
} }
case PTRACE_READTEXT: case PTRACE_READTEXT:
case PTRACE_READDATA: { case PTRACE_READDATA:
int res = ptrace_readdata(child, addr, ret = ptrace_readdata(child, addr,
(char __user *)addr2, data); (char __user *)addr2, data);
if (res == data) { if (ret == data)
pt_succ_return(regs, 0); ret = 0;
goto out_tsk; else if (ret >= 0)
} ret = -EIO;
if (res >= 0) break;
res = -EIO;
pt_error_return(regs, -res);
goto out_tsk;
}
case PTRACE_WRITETEXT: case PTRACE_WRITETEXT:
case PTRACE_WRITEDATA: { case PTRACE_WRITEDATA:
int res = ptrace_writedata(child, (char __user *) addr2, ret = ptrace_writedata(child, (char __user *) addr2,
addr, data); addr, data);
if (res == data) { if (ret == data)
pt_succ_return(regs, 0); ret = 0;
goto out_tsk; else if (ret >= 0)
} ret = -EIO;
if (res >= 0) break;
res = -EIO;
pt_error_return(regs, -res);
goto out_tsk;
}
case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
addr = 1;
case PTRACE_CONT: { /* restart after signal. */
if (!valid_signal(data)) {
pt_error_return(regs, EIO);
goto out_tsk;
}
if (request == PTRACE_SYSCALL) {
set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
} else {
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
}
child->exit_code = data;
#ifdef DEBUG_PTRACE
printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n", child->comm,
child->pid, child->exit_code,
task_pt_regs(child)->tpc,
task_pt_regs(child)->tnpc);
#endif
wake_up_process(child);
pt_succ_return(regs, 0);
goto out_tsk;
}
/*
* 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: {
if (child->exit_state == EXIT_ZOMBIE) { /* already dead */
pt_succ_return(regs, 0);
goto out_tsk;
}
child->exit_code = SIGKILL;
wake_up_process(child);
pt_succ_return(regs, 0);
goto out_tsk;
}
case PTRACE_SUNDETACH: { /* detach a process that was attached. */
int error = ptrace_detach(child, data);
if (error) {
pt_error_return(regs, EIO);
goto out_tsk;
}
pt_succ_return(regs, 0);
goto out_tsk;
}
/* PTRACE_DUMPCORE unsupported... */
case PTRACE_GETEVENTMSG: { case PTRACE_GETEVENTMSG: {
int err;
if (test_thread_flag(TIF_32BIT)) if (test_thread_flag(TIF_32BIT))
err = put_user(child->ptrace_message, ret = put_user(child->ptrace_message,
(unsigned int __user *) data); (unsigned int __user *) data);
else else
err = put_user(child->ptrace_message, ret = put_user(child->ptrace_message,
(unsigned long __user *) data); (unsigned long __user *) data);
if (err)
pt_error_return(regs, -err);
else
pt_succ_return(regs, 0);
break; break;
} }
default: { default:
int err = ptrace_request(child, request, addr, data); ret = ptrace_request(child, request, addr, data);
if (err) break;
pt_error_return(regs, -err);
else
pt_succ_return(regs, 0);
goto out_tsk;
}
} }
out_tsk:
if (child) return ret;
put_task_struct(child);
out:
unlock_kernel();
} }
asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p) asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p)
......
...@@ -48,7 +48,10 @@ void __init prom_init(void *cif_handler, void *cif_stack) ...@@ -48,7 +48,10 @@ void __init prom_init(void *cif_handler, void *cif_stack)
prom_getstring(node, "version", prom_version, sizeof(prom_version)); prom_getstring(node, "version", prom_version, sizeof(prom_version));
prom_printf("\n"); prom_printf("\n");
}
void __init prom_init_report(void)
{
printk("PROMLIB: Sun IEEE Boot Prom '%s'\n", prom_version); printk("PROMLIB: Sun IEEE Boot Prom '%s'\n", prom_version);
printk("PROMLIB: Root node compatible: %s\n", prom_root_compatible); printk("PROMLIB: Root node compatible: %s\n", prom_root_compatible);
} }
...@@ -65,8 +65,14 @@ ...@@ -65,8 +65,14 @@
#define HWCAP_SPARC_V9 16 #define HWCAP_SPARC_V9 16
#define HWCAP_SPARC_ULTRA3 32 #define HWCAP_SPARC_ULTRA3 32
/* For the most part we present code dumps in the format #define CORE_DUMP_USE_REGSET
* Solaris does.
/* Format is:
* G0 --> G7
* O0 --> O7
* L0 --> L7
* I0 --> I7
* PSR, PC, nPC, Y, WIM, TBR
*/ */
typedef unsigned long elf_greg_t; typedef unsigned long elf_greg_t;
#define ELF_NGREG 38 #define ELF_NGREG 38
...@@ -86,34 +92,6 @@ typedef struct { ...@@ -86,34 +92,6 @@ typedef struct {
} elf_fpregset_t; } elf_fpregset_t;
#include <asm/mbus.h> #include <asm/mbus.h>
#include <asm/uaccess.h>
/* Format is:
* G0 --> G7
* O0 --> O7
* L0 --> L7
* I0 --> I7
* PSR, PC, nPC, Y, WIM, TBR
*/
#define ELF_CORE_COPY_REGS(__elf_regs, __pt_regs) \
do { unsigned long *dest = &(__elf_regs[0]); \
struct pt_regs *src = (__pt_regs); \
unsigned long __user *sp; \
memcpy(&dest[0], &src->u_regs[0], \
sizeof(unsigned long) * 16); \
/* Don't try this at home kids... */ \
sp = (unsigned long __user *) src->u_regs[14]; \
copy_from_user(&dest[16], sp, \
sizeof(unsigned long) * 16); \
dest[32] = src->psr; \
dest[33] = src->pc; \
dest[34] = src->npc; \
dest[35] = src->y; \
dest[36] = dest[37] = 0; /* XXX */ \
} while(0); /* Janitors: Don't touch this semicolon. */
#define ELF_CORE_COPY_TASK_REGS(__tsk, __elf_regs) \
({ ELF_CORE_COPY_REGS((*(__elf_regs)), (__tsk)->thread.kregs); 1; })
/* /*
* This is used to ensure we don't load something for the wrong architecture. * This is used to ensure we don't load something for the wrong architecture.
......
...@@ -61,8 +61,6 @@ struct sparc_stackf { ...@@ -61,8 +61,6 @@ struct sparc_stackf {
#ifdef __KERNEL__ #ifdef __KERNEL__
#define __ARCH_SYS_PTRACE 1
#define user_mode(regs) (!((regs)->psr & PSR_PS)) #define user_mode(regs) (!((regs)->psr & PSR_PS))
#define instruction_pointer(regs) ((regs)->pc) #define instruction_pointer(regs) ((regs)->pc)
unsigned long profile_pc(struct pt_regs *); unsigned long profile_pc(struct pt_regs *);
...@@ -151,8 +149,6 @@ extern void show_regs(struct pt_regs *); ...@@ -151,8 +149,6 @@ extern void show_regs(struct pt_regs *);
#define SF_XXARG 0x5c #define SF_XXARG 0x5c
/* Stuff for the ptrace system call */ /* Stuff for the ptrace system call */
#define PTRACE_SUNATTACH 10
#define PTRACE_SUNDETACH 11
#define PTRACE_GETREGS 12 #define PTRACE_GETREGS 12
#define PTRACE_SETREGS 13 #define PTRACE_SETREGS 13
#define PTRACE_GETFPREGS 14 #define PTRACE_GETFPREGS 14
...@@ -164,7 +160,4 @@ extern void show_regs(struct pt_regs *); ...@@ -164,7 +160,4 @@ extern void show_regs(struct pt_regs *);
#define PTRACE_GETFPAREGS 20 #define PTRACE_GETFPAREGS 20
#define PTRACE_SETFPAREGS 21 #define PTRACE_SETFPAREGS 21
#define PTRACE_GETUCODE 29 /* stupid bsd-ism */
#endif /* !(_SPARC_PTRACE_H) */ #endif /* !(_SPARC_PTRACE_H) */
...@@ -70,6 +70,8 @@ ...@@ -70,6 +70,8 @@
#define HWCAP_SPARC_BLKINIT 64 #define HWCAP_SPARC_BLKINIT 64
#define HWCAP_SPARC_N2 128 #define HWCAP_SPARC_N2 128
#define CORE_DUMP_USE_REGSET
/* /*
* These are used to set parameters in the core dumps. * These are used to set parameters in the core dumps.
*/ */
...@@ -78,10 +80,6 @@ ...@@ -78,10 +80,6 @@
#define ELF_CLASS ELFCLASS64 #define ELF_CLASS ELFCLASS64
#define ELF_DATA ELFDATA2MSB #define ELF_DATA ELFDATA2MSB
typedef unsigned long elf_greg_t;
#define ELF_NGREG 36
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
/* Format of 64-bit elf_gregset_t is: /* Format of 64-bit elf_gregset_t is:
* G0 --> G7 * G0 --> G7
* O0 --> O7 * O0 --> O7
...@@ -92,24 +90,9 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG]; ...@@ -92,24 +90,9 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
* TNPC * TNPC
* Y * Y
*/ */
#define ELF_CORE_COPY_REGS(__elf_regs, __pt_regs) \ typedef unsigned long elf_greg_t;
do { unsigned long *dest = &(__elf_regs[0]); \ #define ELF_NGREG 36
struct pt_regs *src = (__pt_regs); \ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
unsigned long __user *sp; \
int i; \
for(i = 0; i < 16; i++) \
dest[i] = src->u_regs[i]; \
/* Don't try this at home kids... */ \
sp = (unsigned long __user *) \
((src->u_regs[14] + STACK_BIAS) \
& 0xfffffffffffffff8UL); \
for(i = 0; i < 16; i++) \
__get_user(dest[i+16], &sp[i]); \
dest[32] = src->tstate; \
dest[33] = src->tpc; \
dest[34] = src->tnpc; \
dest[35] = src->y; \
} while (0);
typedef struct { typedef struct {
unsigned long pr_regs[32]; unsigned long pr_regs[32];
...@@ -119,9 +102,6 @@ typedef struct { ...@@ -119,9 +102,6 @@ typedef struct {
} elf_fpregset_t; } elf_fpregset_t;
#endif #endif
#define ELF_CORE_COPY_TASK_REGS(__tsk, __elf_regs) \
({ ELF_CORE_COPY_REGS((*(__elf_regs)), task_pt_regs(__tsk)); 1; })
/* /*
* This is used to ensure we don't load something for the wrong architecture. * This is used to ensure we don't load something for the wrong architecture.
*/ */
......
...@@ -95,8 +95,6 @@ struct sparc_trapf { ...@@ -95,8 +95,6 @@ struct sparc_trapf {
#ifdef __KERNEL__ #ifdef __KERNEL__
#define __ARCH_SYS_PTRACE 1
#define force_successful_syscall_return() \ #define force_successful_syscall_return() \
do { current_thread_info()->syscall_noerror = 1; \ do { current_thread_info()->syscall_noerror = 1; \
} while (0) } while (0)
...@@ -261,8 +259,6 @@ extern void show_regs(struct pt_regs *); ...@@ -261,8 +259,6 @@ extern void show_regs(struct pt_regs *);
#define SF_XXARG 0x5c #define SF_XXARG 0x5c
/* Stuff for the ptrace system call */ /* Stuff for the ptrace system call */
#define PTRACE_SUNATTACH 10
#define PTRACE_SUNDETACH 11
#define PTRACE_GETREGS 12 #define PTRACE_GETREGS 12
#define PTRACE_SETREGS 13 #define PTRACE_SETREGS 13
#define PTRACE_GETFPREGS 14 #define PTRACE_GETFPREGS 14
...@@ -284,18 +280,4 @@ extern void show_regs(struct pt_regs *); ...@@ -284,18 +280,4 @@ extern void show_regs(struct pt_regs *);
#define PTRACE_GETFPREGS64 25 #define PTRACE_GETFPREGS64 25
#define PTRACE_SETFPREGS64 26 #define PTRACE_SETFPREGS64 26
#define PTRACE_GETUCODE 29 /* stupid bsd-ism */
/* These are for 32-bit processes debugging 64-bit ones.
* Here addr and addr2 are passed in %g2 and %g3 respectively.
*/
#define PTRACE_PEEKTEXT64 (30 + PTRACE_PEEKTEXT)
#define PTRACE_POKETEXT64 (30 + PTRACE_POKETEXT)
#define PTRACE_PEEKDATA64 (30 + PTRACE_PEEKDATA)
#define PTRACE_POKEDATA64 (30 + PTRACE_POKEDATA)
#define PTRACE_READDATA64 (30 + PTRACE_READDATA)
#define PTRACE_WRITEDATA64 (30 + PTRACE_WRITEDATA)
#define PTRACE_READTEXT64 (30 + PTRACE_READTEXT)
#define PTRACE_WRITETEXT64 (30 + PTRACE_WRITETEXT)
#endif /* !(_SPARC64_PTRACE_H) */ #endif /* !(_SPARC64_PTRACE_H) */
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