Suppose that a PTRACE_O_TRACEFORK tracee does fork() and stops in SYSCALL_ENTRY state. The tracer does PTRACE_SINGLESTEP.
In this case the tracee resumes and stops after syscall_trace_leave() to report PTRACE_EVENT_FORK, but since it passes syscall_trace_leave() with TIF_SINGLESTEP set the tracee gets the unwanted send_sigtrap(). Note: of course, this is hack. I think this should be move to utrace layer. Unless we are going to call finish_resume_report(), finish_report() should look at report->action and clear TIF_SINGLESTEP when needed. What do you think? --- kernel/ptrace.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) --- PU/kernel/ptrace.c~128_SUPRESS_UNWANTED_SEND_SIGTRAP 2009-11-02 05:31:46.000000000 +0100 +++ PU/kernel/ptrace.c 2009-11-02 06:16:53.000000000 +0100 @@ -327,6 +327,16 @@ static void ptrace_clone_attach(struct t set_tsk_thread_flag(child, TIF_SIGPENDING); } +/* + * Prevents sending SIGTRAP after tracehook_report_syscall_exit(). + * Called when we are going to emulate the stop before SYSCALL_EXIT. + */ +static void suppress_sigtrap(struct task_struct *task) +{ + if (test_tsk_thread_flag(task, TIF_SINGLESTEP)) + user_disable_single_step(task); +} + static u32 ptrace_report_clone(enum utrace_resume_action action, struct utrace_engine *engine, struct task_struct *parent, @@ -362,6 +372,8 @@ static u32 ptrace_report_clone(enum utra if (!event) return UTRACE_RESUME; + suppress_sigtrap(parent); + set_stop_code(ctx, event); ctx->eventmsg = child->pid; /* @@ -393,8 +405,7 @@ static u32 ptrace_report_syscall_entry(u set_syscall_code(ctx, PTRACE_EVENT_SYSCALL_ENTRY); if (unlikely(ctx->options & PTRACE_O_SYSEMU)) { - if (test_thread_flag(TIF_SINGLESTEP)) - user_disable_single_step(task); + suppress_sigtrap(task); return UTRACE_SYSCALL_ABORT | UTRACE_REPORT; } return UTRACE_SYSCALL_RUN | UTRACE_STOP; @@ -434,6 +445,7 @@ static u32 ptrace_report_exec(enum utrac return UTRACE_RESUME; } + suppress_sigtrap(task); set_stop_code(ctx, PTRACE_EVENT_EXEC); return UTRACE_STOP;