Add ptrace_context->signr. The tracer just sets context->signr = data
and resumes the tracee, the tracee updates context->siginfo if needed.

When the tracee reports the signal it sets context->signr = info->si_signo.
This matches the current behaviour, but perhaps it would be bettter to set
->signr = 0. This only matters if the tracee is killed.

---

 kernel/ptrace.c |   66 ++++++++++++++++++++++++++++----------------------------
 1 file changed, 34 insertions(+), 32 deletions(-)

--- PU/kernel/ptrace.c~61_RESUME_SIGNAL_BY_TRACEE       2009-10-03 
00:00:27.000000000 +0200
+++ PU/kernel/ptrace.c  2009-10-03 01:37:41.000000000 +0200
@@ -27,7 +27,8 @@
 struct ptrace_context {
        int options;
 
-       siginfo_t *siginfo;
+       int             signr;
+       siginfo_t       *siginfo;
 
        int             ev_name;
        int             ev_code;
@@ -262,23 +263,37 @@ static u32 ptrace_report_exec(enum utrac
        return UTRACE_STOP;
 }
 
-/*
- * XXX: This all is wrong/racy/crashable
- */
-static void ptrace_resume_signal(struct ptrace_context* context, int data)
+static enum utrace_signal_action resume_signal(struct task_struct *task,
+                                               int signr, siginfo_t *info,
+                                               struct k_sigaction *return_ka)
 {
-       siginfo_t *info = context->siginfo;
-
-       if (WARN_ON(!info))
-               return;
-
-       if (info->si_signo != data) {
-               info->si_signo = data;
-               info->si_code = SI_USER;
+       /* Did the debugger cancel the sig? */
+       if (!signr)
+               return UTRACE_SIGNAL_IGN;
+       /*
+        * Update the siginfo structure if the signal has changed.
+        * If the debugger wanted something specific in the siginfo
+        * then it should have updated *info via PTRACE_SETSIGINFO.
+        */
+       if (info->si_signo != signr) {
+               info->si_signo = signr;
                info->si_errno = 0;
-               info->si_pid = task_pid_vnr(current);
-               info->si_uid = current_uid();
+               info->si_code = SI_USER;
+               info->si_pid = task_pid_vnr(current->parent);
+               info->si_uid = task_uid(current->parent);
        }
+
+       /* If the (new) signal is now blocked, requeue it. */
+       if (sigismember(&task->blocked, signr)) {
+               send_sig_info(signr, info, task);
+               return UTRACE_SIGNAL_IGN;
+       }
+
+       spin_lock_irq(&task->sighand->siglock);
+       *return_ka = task->sighand->action[signr - 1];
+       spin_unlock_irq(&task->sighand->siglock);
+
+       return UTRACE_SIGNAL_DELIVER;
 }
 
 static u32 ptrace_report_signal(u32 action,
@@ -319,22 +334,8 @@ static u32 ptrace_report_signal(u32 acti
                        return resume | UTRACE_SIGNAL_IGN;
                context->siginfo = NULL;
 
-               if (!info->si_signo) // debugger cancelled sig
-                       return resume | UTRACE_SIGNAL_IGN;
-               /*
-                * If the (new) signal is now blocked, requeue it.
-                */
-               if (sigismember(&task->blocked, info->si_signo)) {
-                       send_sig_info(info->si_signo, info, task);
-                       return resume | UTRACE_SIGNAL_IGN;
-               }
-
-               spin_lock_irq(&task->sighand->siglock);
-               *return_ka = task->sighand->action[info->si_signo - 1];
-               spin_unlock_irq(&task->sighand->siglock);
-
-               return resume | UTRACE_SIGNAL_DELIVER;
-
+               return resume | resume_signal(task, context->signr,
+                                               info, return_ka);
        default:
                WARN_ON(context->siginfo);
                context->siginfo = info;
@@ -344,6 +345,7 @@ static u32 ptrace_report_signal(u32 acti
 
                context->ev_name = PTRACE_EVENT_SIGNAL;
                context->ev_code = info->si_signo;
+               context->signr   = info->si_signo;
 
                return UTRACE_STOP | UTRACE_SIGNAL_IGN;
        }
@@ -895,7 +897,7 @@ static void do_ptrace_resume(struct utra
                        send_sig_info(data, SEND_SIG_PRIV, tracee);
                break;
        case PTRACE_EVENT_SIGNAL:
-               ptrace_resume_signal(context, data);
+               context->signr = data;
                break;
        }
 

Reply via email to