Introduce xxx_utrace_stop() which notifies engine we are going to stop.
It calls report_quiesce(0), but report.action = UTRACE_STOP instead of
UTRACE_RESUME.

Change ptrace_stop() to use xxx_utrace_stop(). Yes, it is racy and can
stop after detach, but afaics this is fixeable when utrace_stop() will
be fixed.

Change utrace_stop() to use another ugly hack, xxx_ptrace_notify_stop(),
to notify the parent.

---

 include/linux/sched.h  |    1 +
 include/linux/utrace.h |    3 +++
 include/linux/ptrace.h |    4 ++++
 kernel/utrace.c        |   20 ++++++++++++++++++++
 kernel/ptrace.c        |   36 ++++++++++++++++++++++++++++++++++++
 kernel/signal.c        |   24 +++---------------------
 6 files changed, 67 insertions(+), 21 deletions(-)

--- MINI/include/linux/sched.h~3_PTRACE_NOTIFY  2009-08-25 17:00:35.000000000 
+0200
+++ MINI/include/linux/sched.h  2009-08-25 17:11:38.000000000 +0200
@@ -1980,6 +1980,7 @@ extern int kill_pgrp(struct pid *pid, in
 extern int kill_pid(struct pid *pid, int sig, int priv);
 extern int kill_proc_info(int, struct siginfo *, pid_t);
 extern int do_notify_parent(struct task_struct *, int);
+extern void do_notify_parent_cldstop(struct task_struct *, int);
 extern void force_sig(int, struct task_struct *);
 extern void force_sig_specific(int, struct task_struct *);
 extern int send_sig(int, struct task_struct *, int);
--- MINI/include/linux/utrace.h~3_PTRACE_NOTIFY 2009-08-17 11:56:56.000000000 
+0200
+++ MINI/include/linux/utrace.h 2009-08-25 17:20:24.000000000 +0200
@@ -624,6 +624,9 @@ int __must_check utrace_finish_examine(s
                                       struct utrace_engine *,
                                       struct utrace_examiner *);
 
+void xxx_utrace_stop(void);
+
+
 /**
  * utrace_control_pid - control a thread being traced by a tracing engine
  * @pid:               thread to affect
--- MINI/include/linux/ptrace.h~3_PTRACE_NOTIFY 2009-08-25 17:00:35.000000000 
+0200
+++ MINI/include/linux/ptrace.h 2009-08-25 17:35:45.000000000 +0200
@@ -94,6 +94,10 @@ extern void __ptrace_link(struct task_st
                          struct task_struct *new_parent);
 extern void __ptrace_unlink(struct task_struct *child);
 extern void exit_ptrace(struct task_struct *tracer);
+
+extern void ptrace_do_stop(void);
+void xxx_ptrace_notify_stop(struct task_struct *);
+
 #define PTRACE_MODE_READ   1
 #define PTRACE_MODE_ATTACH 2
 /* Returns 0 on success, -errno on denial. */
--- MINI/kernel/utrace.c~3_PTRACE_NOTIFY        2009-08-25 12:33:17.000000000 
+0200
+++ MINI/kernel/utrace.c        2009-08-25 17:33:51.000000000 +0200
@@ -398,6 +398,9 @@ static void utrace_stop(struct task_stru
        spin_unlock_irq(&task->sighand->siglock);
        spin_unlock(&utrace->lock);
 
+       if (task_ptrace(task))
+               xxx_ptrace_notify_stop(task);
+
        schedule();
 
        /*
@@ -1819,6 +1822,23 @@ void utrace_resume(struct task_struct *t
        finish_resume_report(&report, task, utrace);
 }
 
+void xxx_utrace_stop(void)
+{
+       struct task_struct *task = current;
+       struct utrace *utrace = task_utrace_struct(task);
+       struct utrace_engine *engine;
+       INIT_REPORT(report);
+
+       report.action = UTRACE_STOP;
+
+       start_report(utrace);
+
+       list_for_each_entry(engine, &utrace->attached, entry)
+               start_callback(utrace, &report, engine, task, 0);
+
+       finish_resume_report(&report, task, utrace);
+}
+
 /*
  * Return true if current has forced signal_pending().
  *
--- MINI/kernel/ptrace.c~3_PTRACE_NOTIFY        2009-08-25 17:00:35.000000000 
+0200
+++ MINI/kernel/ptrace.c        2009-08-25 17:41:47.000000000 +0200
@@ -62,6 +62,42 @@ static int ptrace_attach_task(struct tas
        return 0;
 }
 
+void ptrace_do_stop(void)
+{
+       struct utrace_engine *engine;
+
+       engine = utrace_attach_task(current, UTRACE_ATTACH_MATCH_OPS,
+                                   &ptrace_utrace_ops, NULL);
+       if (unlikely(IS_ERR(engine)))
+               return;
+
+       utrace_control(current, engine, UTRACE_STOP); /* unneeded curently */
+
+       engine->data = (void*)1; /* marker for xxx_ptrace_notify_stop() */
+       xxx_utrace_stop();
+       engine->data = NULL;
+
+       utrace_engine_put(engine);
+}
+
+void xxx_ptrace_notify_stop(struct task_struct *task)
+{
+       struct utrace_engine *engine;
+
+       engine = utrace_attach_task(task, UTRACE_ATTACH_MATCH_OPS,
+                                   &ptrace_utrace_ops, NULL);
+       if (unlikely(IS_ERR(engine)))
+               return;
+
+       if (engine->data) {
+               read_lock(&tasklist_lock);
+               do_notify_parent_cldstop(task, CLD_TRAPPED);
+               read_unlock(&tasklist_lock);
+       }
+
+       utrace_engine_put(engine);
+}
+
 /*
  * ptrace a task: make the debugger its new parent and
  * move it to the ptrace list.
--- MINI/kernel/signal.c~3_PTRACE_NOTIFY        2009-08-25 17:00:35.000000000 
+0200
+++ MINI/kernel/signal.c        2009-08-25 17:11:38.000000000 +0200
@@ -1479,7 +1479,7 @@ int do_notify_parent(struct task_struct 
        return ret;
 }
 
-static void do_notify_parent_cldstop(struct task_struct *tsk, int why)
+void do_notify_parent_cldstop(struct task_struct *tsk, int why)
 {
        struct siginfo info;
        unsigned long flags;
@@ -1595,32 +1595,14 @@ static void ptrace_stop(int exit_code, i
                        return;
        }
 
-       /*
-        * If there is a group stop in progress,
-        * we must participate in the bookkeeping.
-        */
-       if (current->signal->group_stop_count > 0)
-               --current->signal->group_stop_count;
-
        current->last_siginfo = info;
        current->exit_code = exit_code;
-
-       /* Let the debugger run.  */
-       __set_current_state(TASK_TRACED);
        spin_unlock_irq(&current->sighand->siglock);
        read_lock(&tasklist_lock);
        if (may_ptrace_stop()) {
-               do_notify_parent_cldstop(current, CLD_TRAPPED);
-               /*
-                * Don't want to allow preemption here, because
-                * sys_ptrace() needs this task to be inactive.
-                *
-                * XXX: implement read_unlock_no_resched().
-                */
-               preempt_disable();
                read_unlock(&tasklist_lock);
-               preempt_enable_no_resched();
-               schedule();
+
+               ptrace_do_stop();
        } else {
                /*
                 * By the time we got the lock, our tracer went away.

Reply via email to