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;