/*
* Kernel support for the ptrace() and syscall tracing interfaces.
*
- * Copyright (C) 1999-2003 Hewlett-Packard Co
+ * Copyright (C) 1999-2004 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com>
*
* Derived from the x86 and Alpha versions. Most of the code in here
ri = 0;
regs->cr_iip += 16;
} else if (ri == 2) {
- get_user(w0, (char *) regs->cr_iip + 0);
+ get_user(w0, (char __user *) regs->cr_iip + 0);
if (((w0 >> 1) & 0xf) == IA64_MLX_TEMPLATE) {
/*
* rfi'ing to slot 2 of an MLX bundle causes
if (ia64_psr(regs)->ri == 0) {
regs->cr_iip -= 16;
ri = 2;
- get_user(w0, (char *) regs->cr_iip + 0);
+ get_user(w0, (char __user *) regs->cr_iip + 0);
if (((w0 >> 1) & 0xf) == IA64_MLX_TEMPLATE) {
/*
* rfi'ing to slot 2 of an MLX bundle causes
long num_regs, nbits;
struct pt_regs *pt;
unsigned long cfm, *urbs_kargs;
- struct unw_frame_info info;
pt = ia64_task_regs(task);
kbsp = (unsigned long *) sw->ar_bspstore;
* If entered via syscall, don't allow user to set rnat bits
* for syscall args.
*/
- unw_init_from_blocked_task(&info,task);
- if (unw_unwind_to_user(&info) == 0) {
- unw_get_cfm(&info,&cfm);
- urbs_kargs = ia64_rse_skip_regs(urbs_end,-(cfm & 0x7f));
- }
+ cfm = pt->cr_ifs;
+ urbs_kargs = ia64_rse_skip_regs(urbs_end, -(cfm & 0x7f));
}
if (urbs_kargs >= urnat_addr)
unsigned long
ia64_get_user_rbs_end (struct task_struct *child, struct pt_regs *pt, unsigned long *cfmp)
{
- unsigned long *krbs, *bspstore, cfm;
- struct unw_frame_info info;
+ unsigned long *krbs, *bspstore, cfm = pt->cr_ifs;
long ndirty;
krbs = (unsigned long *) child + IA64_RBS_OFFSET/8;
bspstore = (unsigned long *) pt->ar_bspstore;
ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19));
- cfm = pt->cr_ifs & ~(1UL << 63);
- if (in_syscall(pt)) {
- /*
- * If bit 63 of cr.ifs is cleared, the kernel was entered via a system
- * call and we need to recover the CFM that existed on entry to the
- * kernel by unwinding the kernel stack.
- */
- unw_init_from_blocked_task(&info, child);
- if (unw_unwind_to_user(&info) == 0) {
- unw_get_cfm(&info, &cfm);
- ndirty += (cfm & 0x7f);
- }
- }
+ if (in_syscall(pt))
+ ndirty += (cfm & 0x7f);
+ else
+ cfm &= ~(1UL << 63); /* clear valid bit */
+
if (cfmp)
*cfmp = cfm;
return (unsigned long) ia64_rse_skip_regs(bspstore, ndirty);
case PT_CFM:
urbs_end = ia64_get_user_rbs_end(child, pt, &cfm);
if (write_access) {
- if (((cfm ^ *data) & 0x3fffffffffU) != 0) {
+ if (((cfm ^ *data) & 0x3fffffffffUL) != 0) {
if (ia64_sync_user_rbs(child, sw,
pt->ar_bspstore, urbs_end) < 0)
return -1;
}
static long
-ptrace_getregs (struct task_struct *child, struct pt_all_user_regs *ppr)
+ptrace_getregs (struct task_struct *child, struct pt_all_user_regs __user *ppr)
{
+ unsigned long psr, ec, lc, rnat, bsp, cfm, nat_bits, val;
+ struct unw_frame_info info;
+ struct ia64_fpreg fpval;
struct switch_stack *sw;
struct pt_regs *pt;
long ret, retval;
- struct unw_frame_info info;
char nat = 0;
int i;
return -EIO;
}
+ if (access_uarea(child, PT_CR_IPSR, &psr, 0) < 0
+ || access_uarea(child, PT_AR_EC, &ec, 0) < 0
+ || access_uarea(child, PT_AR_LC, &lc, 0) < 0
+ || access_uarea(child, PT_AR_RNAT, &rnat, 0) < 0
+ || access_uarea(child, PT_AR_BSP, &bsp, 0) < 0
+ || access_uarea(child, PT_CFM, &cfm, 0)
+ || access_uarea(child, PT_NAT_BITS, &nat_bits, 0))
+ return -EIO;
+
retval = 0;
/* control regs */
retval |= __put_user(pt->cr_iip, &ppr->cr_iip);
- retval |= access_uarea(child, PT_CR_IPSR, &ppr->cr_ipsr, 0);
+ retval |= __put_user(psr, &ppr->cr_ipsr);
/* app regs */
retval |= __put_user(pt->ar_ccv, &ppr->ar[PT_AUR_CCV]);
retval |= __put_user(pt->ar_fpsr, &ppr->ar[PT_AUR_FPSR]);
- retval |= access_uarea(child, PT_AR_EC, &ppr->ar[PT_AUR_EC], 0);
- retval |= access_uarea(child, PT_AR_LC, &ppr->ar[PT_AUR_LC], 0);
- retval |= access_uarea(child, PT_AR_RNAT, &ppr->ar[PT_AUR_RNAT], 0);
- retval |= access_uarea(child, PT_AR_BSP, &ppr->ar[PT_AUR_BSP], 0);
- retval |= access_uarea(child, PT_CFM, &ppr->cfm, 0);
+ retval |= __put_user(ec, &ppr->ar[PT_AUR_EC]);
+ retval |= __put_user(lc, &ppr->ar[PT_AUR_LC]);
+ retval |= __put_user(rnat, &ppr->ar[PT_AUR_RNAT]);
+ retval |= __put_user(bsp, &ppr->ar[PT_AUR_BSP]);
+ retval |= __put_user(cfm, &ppr->cfm);
/* gr1-gr3 */
/* gr4-gr7 */
for (i = 4; i < 8; i++) {
- retval |= unw_access_gr(&info, i, &ppr->gr[i], &nat, 0);
+ if (unw_access_gr(&info, i, &val, &nat, 0) < 0)
+ return -EIO;
+ retval |= __put_user(val, &ppr->gr[i]);
}
/* gr8-gr11 */
/* b1-b5 */
for (i = 1; i < 6; i++) {
- retval |= unw_access_br(&info, i, &ppr->br[i], 0);
+ if (unw_access_br(&info, i, &val, 0) < 0)
+ return -EIO;
+ __put_user(val, &ppr->br[i]);
}
/* b6-b7 */
/* fr2-fr5 */
for (i = 2; i < 6; i++) {
- retval |= access_fr(&info, i, 0, (unsigned long *) &ppr->fr[i], 0);
- retval |= access_fr(&info, i, 1, (unsigned long *) &ppr->fr[i] + 1, 0);
+ if (unw_get_fr(&info, i, &fpval) < 0)
+ return -EIO;
+ retval |= __copy_to_user(&ppr->fr[i], &fpval, sizeof (fpval));
}
/* fr6-fr11 */
/* fr16-fr31 */
for (i = 16; i < 32; i++) {
- retval |= access_fr(&info, i, 0, (unsigned long *) &ppr->fr[i], 0);
- retval |= access_fr(&info, i, 1, (unsigned long *) &ppr->fr[i] + 1, 0);
+ if (unw_get_fr(&info, i, &fpval) < 0)
+ return -EIO;
+ retval |= __copy_to_user(&ppr->fr[i], &fpval, sizeof (fpval));
}
/* fph */
/* nat bits */
- retval |= access_uarea(child, PT_NAT_BITS, &ppr->nat, 0);
+ retval |= __put_user(nat_bits, &ppr->nat);
ret = retval ? -EIO : 0;
return ret;
}
static long
-ptrace_setregs (struct task_struct *child, struct pt_all_user_regs *ppr)
+ptrace_setregs (struct task_struct *child, struct pt_all_user_regs __user *ppr)
{
+ unsigned long psr, ec, lc, rnat, bsp, cfm, nat_bits, val = 0;
+ struct unw_frame_info info;
struct switch_stack *sw;
+ struct ia64_fpreg fpval;
struct pt_regs *pt;
long ret, retval;
- struct unw_frame_info info;
- char nat = 0;
int i;
+ memset(&fpval, 0, sizeof(fpval));
+
retval = verify_area(VERIFY_READ, ppr, sizeof(struct pt_all_user_regs));
if (retval != 0) {
return -EIO;
/* control regs */
retval |= __get_user(pt->cr_iip, &ppr->cr_iip);
- retval |= access_uarea(child, PT_CR_IPSR, &ppr->cr_ipsr, 1);
+ retval |= __get_user(psr, &ppr->cr_ipsr);
/* app regs */
retval |= __get_user(pt->ar_ccv, &ppr->ar[PT_AUR_CCV]);
retval |= __get_user(pt->ar_fpsr, &ppr->ar[PT_AUR_FPSR]);
- retval |= access_uarea(child, PT_AR_EC, &ppr->ar[PT_AUR_EC], 1);
- retval |= access_uarea(child, PT_AR_LC, &ppr->ar[PT_AUR_LC], 1);
- retval |= access_uarea(child, PT_AR_RNAT, &ppr->ar[PT_AUR_RNAT], 1);
- retval |= access_uarea(child, PT_AR_BSP, &ppr->ar[PT_AUR_BSP], 1);
- retval |= access_uarea(child, PT_CFM, &ppr->cfm, 1);
+ retval |= __get_user(ec, &ppr->ar[PT_AUR_EC]);
+ retval |= __get_user(lc, &ppr->ar[PT_AUR_LC]);
+ retval |= __get_user(rnat, &ppr->ar[PT_AUR_RNAT]);
+ retval |= __get_user(bsp, &ppr->ar[PT_AUR_BSP]);
+ retval |= __get_user(cfm, &ppr->cfm);
/* gr1-gr3 */
/* gr4-gr7 */
for (i = 4; i < 8; i++) {
- long ret = unw_get_gr(&info, i, &ppr->gr[i], &nat);
- if (ret < 0) {
- return ret;
- }
- retval |= unw_access_gr(&info, i, &ppr->gr[i], &nat, 1);
+ retval |= __get_user(val, &ppr->gr[i]);
+ if (unw_set_gr(&info, i, val, 0) < 0) /* NaT bit will be set via PT_NAT_BITS */
+ return -EIO;
}
/* gr8-gr11 */
/* b1-b5 */
for (i = 1; i < 6; i++) {
- retval |= unw_access_br(&info, i, &ppr->br[i], 1);
+ retval |= __get_user(val, &ppr->br[i]);
+ unw_set_br(&info, i, val);
}
/* b6-b7 */
/* fr2-fr5 */
for (i = 2; i < 6; i++) {
- retval |= access_fr(&info, i, 0, (unsigned long *) &ppr->fr[i], 1);
- retval |= access_fr(&info, i, 1, (unsigned long *) &ppr->fr[i] + 1, 1);
+ retval |= __copy_from_user(&fpval, &ppr->fr[i], sizeof(fpval));
+ if (unw_set_fr(&info, i, fpval) < 0)
+ return -EIO;
}
/* fr6-fr11 */
/* fr16-fr31 */
for (i = 16; i < 32; i++) {
- retval |= access_fr(&info, i, 0, (unsigned long *) &ppr->fr[i], 1);
- retval |= access_fr(&info, i, 1, (unsigned long *) &ppr->fr[i] + 1, 1);
+ retval |= __copy_from_user(&fpval, &ppr->fr[i], sizeof(fpval));
+ if (unw_set_fr(&info, i, fpval) < 0)
+ return -EIO;
}
/* fph */
/* nat bits */
- retval |= access_uarea(child, PT_NAT_BITS, &ppr->nat, 1);
+ retval |= __get_user(nat_bits, &ppr->nat);
+
+ retval |= access_uarea(child, PT_CR_IPSR, &psr, 1);
+ retval |= access_uarea(child, PT_AR_EC, &ec, 1);
+ retval |= access_uarea(child, PT_AR_LC, &lc, 1);
+ retval |= access_uarea(child, PT_AR_RNAT, &rnat, 1);
+ retval |= access_uarea(child, PT_AR_BSP, &bsp, 1);
+ retval |= access_uarea(child, PT_CFM, &cfm, 1);
+ retval |= access_uarea(child, PT_NAT_BITS, &nat_bits, 1);
ret = retval ? -EIO : 0;
return ret;
* sigkill. Perhaps it should be put in the status
* that it wants to exit.
*/
- if (child->state == TASK_ZOMBIE) /* already dead */
+ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
goto out_tsk;
child->exit_code = SIGKILL;
goto out_tsk;
case PTRACE_GETREGS:
- ret = ptrace_getregs(child, (struct pt_all_user_regs*) data);
+ ret = ptrace_getregs(child, (struct pt_all_user_regs __user *) data);
goto out_tsk;
case PTRACE_SETREGS:
- ret = ptrace_setregs(child, (struct pt_all_user_regs*) data);
+ ret = ptrace_setregs(child, (struct pt_all_user_regs __user *) data);
goto out_tsk;
default:
return ret;
}
-/* "asmlinkage" so the input arguments are preserved... */
-asmlinkage void
+void
syscall_trace (void)
{
if (!test_thread_flag(TIF_SYSCALL_TRACE))
current->exit_code = 0;
}
}
+
+/* "asmlinkage" so the input arguments are preserved... */
+
+asmlinkage void
+syscall_trace_enter (long arg0, long arg1, long arg2, long arg3,
+ long arg4, long arg5, long arg6, long arg7, long stack)
+{
+ struct pt_regs *regs = (struct pt_regs *) &stack;
+ long syscall;
+
+ if (unlikely(current->audit_context)) {
+ if (IS_IA32_PROCESS(regs))
+ syscall = regs->r1;
+ else
+ syscall = regs->r15;
+
+ audit_syscall_entry(current, syscall, arg0, arg1, arg2, arg3);
+ }
+
+ if (test_thread_flag(TIF_SYSCALL_TRACE) && (current->ptrace & PT_PTRACED))
+ syscall_trace();
+}
+
+/* "asmlinkage" so the input arguments are preserved... */
+
+asmlinkage void
+syscall_trace_leave (long arg0, long arg1, long arg2, long arg3,
+ long arg4, long arg5, long arg6, long arg7, long stack)
+{
+ if (unlikely(current->audit_context))
+ audit_syscall_exit(current, ((struct pt_regs *) &stack)->r8);
+
+ if (test_thread_flag(TIF_SYSCALL_TRACE) && (current->ptrace & PT_PTRACED))
+ syscall_trace();
+}