[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(¤t->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