[PATCH 3] utrace-ptrace-mini: ptrace_stop: make it utrace-friendly

Oleg Nesterov oleg at redhat.com
Tue Aug 25 16:52:46 UTC 2009


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.




More information about the utrace-devel mailing list