]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - arch/x86/kernel/ptrace.c
Merge commit 'v2.6.33' into perf/core
[net-next-2.6.git] / arch / x86 / kernel / ptrace.c
index 7079ddaf0731e949d99940f7a036d82f3b613954..d03146f71b2f21becd387c5fe7297c8318b5f584 100644 (file)
@@ -140,30 +140,6 @@ static const int arg_offs_table[] = {
 #endif
 };
 
-/**
- * regs_get_argument_nth() - get Nth argument at function call
- * @regs:      pt_regs which contains registers at function entry.
- * @n:         argument number.
- *
- * regs_get_argument_nth() returns @n th argument of a function call.
- * Since usually the kernel stack will be changed right after function entry,
- * you must use this at function entry. If the @n th entry is NOT in the
- * kernel stack or pt_regs, this returns 0.
- */
-unsigned long regs_get_argument_nth(struct pt_regs *regs, unsigned int n)
-{
-       if (n < ARRAY_SIZE(arg_offs_table))
-               return *(unsigned long *)((char *)regs + arg_offs_table[n]);
-       else {
-               /*
-                * The typical case: arg n is on the stack.
-                * (Note: stack[0] = return address, so skip it)
-                */
-               n -= ARRAY_SIZE(arg_offs_table);
-               return regs_get_kernel_stack_nth(regs, 1 + n);
-       }
-}
-
 /*
  * does not yet catch signals sent when the child dies.
  * in exit.c or in signal.c.
@@ -509,14 +485,14 @@ static int genregs_get(struct task_struct *target,
 {
        if (kbuf) {
                unsigned long *k = kbuf;
-               while (count > 0) {
+               while (count >= sizeof(*k)) {
                        *k++ = getreg(target, pos);
                        count -= sizeof(*k);
                        pos += sizeof(*k);
                }
        } else {
                unsigned long __user *u = ubuf;
-               while (count > 0) {
+               while (count >= sizeof(*u)) {
                        if (__put_user(getreg(target, pos), u++))
                                return -EFAULT;
                        count -= sizeof(*u);
@@ -535,14 +511,14 @@ static int genregs_set(struct task_struct *target,
        int ret = 0;
        if (kbuf) {
                const unsigned long *k = kbuf;
-               while (count > 0 && !ret) {
+               while (count >= sizeof(*k) && !ret) {
                        ret = putreg(target, pos, *k++);
                        count -= sizeof(*k);
                        pos += sizeof(*k);
                }
        } else {
                const unsigned long  __user *u = ubuf;
-               while (count > 0 && !ret) {
+               while (count >= sizeof(*u) && !ret) {
                        unsigned long word;
                        ret = __get_user(word, u++);
                        if (ret)
@@ -702,7 +678,7 @@ static unsigned long ptrace_get_debugreg(struct task_struct *tsk, int n)
        } else if (n == 6) {
                val = thread->debugreg6;
         } else if (n == 7) {
-               val = ptrace_get_dr7(thread->ptrace_bps);
+               val = thread->ptrace_dr7;
        }
        return val;
 }
@@ -778,8 +754,11 @@ int ptrace_set_debugreg(struct task_struct *tsk, int n, unsigned long val)
                        return rc;
        }
        /* All that's left is DR7 */
-       if (n == 7)
+       if (n == 7) {
                rc = ptrace_write_dr7(tsk, val);
+               if (!rc)
+                       thread->ptrace_dr7 = val;
+       }
 
 ret_path:
        return rc;
@@ -1458,14 +1437,14 @@ static int genregs32_get(struct task_struct *target,
 {
        if (kbuf) {
                compat_ulong_t *k = kbuf;
-               while (count > 0) {
+               while (count >= sizeof(*k)) {
                        getreg32(target, pos, k++);
                        count -= sizeof(*k);
                        pos += sizeof(*k);
                }
        } else {
                compat_ulong_t __user *u = ubuf;
-               while (count > 0) {
+               while (count >= sizeof(*u)) {
                        compat_ulong_t word;
                        getreg32(target, pos, &word);
                        if (__put_user(word, u++))
@@ -1486,14 +1465,14 @@ static int genregs32_set(struct task_struct *target,
        int ret = 0;
        if (kbuf) {
                const compat_ulong_t *k = kbuf;
-               while (count > 0 && !ret) {
+               while (count >= sizeof(*k) && !ret) {
                        ret = putreg32(target, pos, *k++);
                        count -= sizeof(*k);
                        pos += sizeof(*k);
                }
        } else {
                const compat_ulong_t __user *u = ubuf;
-               while (count > 0 && !ret) {
+               while (count >= sizeof(*u) && !ret) {
                        compat_ulong_t word;
                        ret = __get_user(word, u++);
                        if (ret)
@@ -1676,21 +1655,33 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task)
 #endif
 }
 
-void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
-                                        int error_code, int si_code)
+static void fill_sigtrap_info(struct task_struct *tsk,
+                               struct pt_regs *regs,
+                               int error_code, int si_code,
+                               struct siginfo *info)
 {
-       struct siginfo info;
-
        tsk->thread.trap_no = 1;
        tsk->thread.error_code = error_code;
 
-       memset(&info, 0, sizeof(info));
-       info.si_signo = SIGTRAP;
-       info.si_code = si_code;
+       memset(info, 0, sizeof(*info));
+       info->si_signo = SIGTRAP;
+       info->si_code = si_code;
+       info->si_addr = user_mode_vm(regs) ? (void __user *)regs->ip : NULL;
+}
+
+void user_single_step_siginfo(struct task_struct *tsk,
+                               struct pt_regs *regs,
+                               struct siginfo *info)
+{
+       fill_sigtrap_info(tsk, regs, 0, TRAP_BRKPT, info);
+}
 
-       /* User-mode ip? */
-       info.si_addr = user_mode_vm(regs) ? (void __user *) regs->ip : NULL;
+void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
+                                        int error_code, int si_code)
+{
+       struct siginfo info;
 
+       fill_sigtrap_info(tsk, regs, error_code, si_code, &info);
        /* Send us the fake SIGTRAP */
        force_sig_info(SIGTRAP, &info, tsk);
 }
@@ -1755,29 +1746,22 @@ asmregparm long syscall_trace_enter(struct pt_regs *regs)
 
 asmregparm void syscall_trace_leave(struct pt_regs *regs)
 {
+       bool step;
+
        if (unlikely(current->audit_context))
                audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
 
        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
                trace_sys_exit(regs, regs->ax);
 
-       if (test_thread_flag(TIF_SYSCALL_TRACE))
-               tracehook_report_syscall_exit(regs, 0);
-
        /*
         * If TIF_SYSCALL_EMU is set, we only get here because of
         * TIF_SINGLESTEP (i.e. this is PTRACE_SYSEMU_SINGLESTEP).
         * We already reported this syscall instruction in
-        * syscall_trace_enter(), so don't do any more now.
-        */
-       if (unlikely(test_thread_flag(TIF_SYSCALL_EMU)))
-               return;
-
-       /*
-        * If we are single-stepping, synthesize a trap to follow the
-        * system call instruction.
+        * syscall_trace_enter().
         */
-       if (test_thread_flag(TIF_SINGLESTEP) &&
-           tracehook_consider_fatal_signal(current, SIGTRAP))
-               send_sigtrap(current, regs, 0, TRAP_BRKPT);
+       step = unlikely(test_thread_flag(TIF_SINGLESTEP)) &&
+                       !test_thread_flag(TIF_SYSCALL_EMU);
+       if (step || test_thread_flag(TIF_SYSCALL_TRACE))
+               tracehook_report_syscall_exit(regs, step);
 }