Change ptrace_report_signal() to use ptrace_event.

Very preliminary change, just to make the first step. "strace /bin/true"
works, and I guess nothing else. And even this wasn't trivial to me ;)

Further changes:

        - remove the old and now unneeded code

        - teach ptrace_resume() to handle jctl stops

        - actually implement signals handling, step by step

---

 kernel/ptrace.c |   65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)

--- PU/kernel/ptrace.c~43_REPORT_SIGNAL_DRAFT   2009-09-16 15:08:28.000000000 
+0200
+++ PU/kernel/ptrace.c  2009-09-16 20:14:57.000000000 +0200
@@ -424,6 +424,27 @@ static u32 ptrace_resumed(struct task_st
        return UTRACE_SIGNAL_DELIVER | resume;
 }
 
+/*
+ * XXX: This all is wrong/racy/crashable
+ */
+
+static void ptrace_resume_signal(struct utrace_engine *engine,
+                                       struct task_struct *tracee, long data)
+{
+       siginfo_t *info = tracee->last_siginfo;
+
+       if (WARN_ON(!info))
+               return;
+
+       if (info->si_signo != data) {
+               info->si_signo = data;
+               info->si_code = SI_USER;
+               info->si_errno = 0;
+               info->si_pid = task_pid_vnr(current);
+               info->si_uid = current_uid();
+       }
+}
+
 static u32 ptrace_report_signal(u32 action,
                                struct utrace_engine *engine,
                                struct task_struct *task,
@@ -433,6 +454,7 @@ static u32 ptrace_report_signal(u32 acti
                                struct k_sigaction *return_ka)
 {
        struct ptrace_context *context = ptrace_context(engine);
+       struct ptrace_event *ev;
 
        if (!ev_empty(context)) {
                WARN_ON(!ev_current(context)->ev_code && 
!fatal_signal_pending(task));
@@ -442,6 +464,49 @@ static u32 ptrace_report_signal(u32 acti
        }
 
        switch (utrace_signal_action(action)) {
+       case UTRACE_SIGNAL_HANDLER:
+               WARN_ON(1);
+       case UTRACE_SIGNAL_REPORT:
+               if (!task->last_siginfo)
+                       return UTRACE_RESUME | UTRACE_SIGNAL_IGN;
+
+               if (WARN_ON(task->last_siginfo != info))
+                       return UTRACE_RESUME | UTRACE_SIGNAL_IGN;
+               task->last_siginfo = NULL;
+
+               if (!info->si_signo) // debugger cancelled sig
+                       return UTRACE_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 UTRACE_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 UTRACE_RESUME | UTRACE_SIGNAL_DELIVER;
+
+       default:
+               WARN_ON(task->last_siginfo);
+               task->last_siginfo = info;
+               // Make sure the next UTRACE_SIGNAL_REPORT
+               // will clear ->last_siginfo
+               utrace_control(task, engine, UTRACE_INTERRUPT);
+
+               ev = ev_push(context);
+               ev->ev_resume = ptrace_resume_signal;
+               ev->ev_code = info->si_signo;
+
+               return UTRACE_STOP | UTRACE_SIGNAL_IGN;
+       }
+
+       // everything below is dead
+
+       switch (utrace_signal_action(action)) {
        default:
                WARN_ON(ptrace_stop_event(task) && info->si_signo != SIGKILL);
                break;

Reply via email to