Extract arch_fill_sigtrap_info() from send_sigtrap() and change syscall_trace_leave() to rely on tracehook_report_syscall_exit() to handle stepping.
Note: before this patch x86 generated the unnecessary SIGTRAP when PTRACE_SINGLESTEP done at the syscall-exit stop, now x86 matches other architectures. --- arch/x86/include/asm/ptrace.h | 5 ++++ arch/x86/kernel/ptrace.c | 51 +++++++++++++++++++++++------------------- 2 files changed, 33 insertions(+), 23 deletions(-) --- TH/arch/x86/include/asm/ptrace.h~2_CONVERT_X86 2009-06-11 14:16:46.000000000 +0200 +++ TH/arch/x86/include/asm/ptrace.h 2009-11-08 20:45:21.000000000 +0100 @@ -230,6 +230,11 @@ extern void user_enable_block_step(struc #define arch_has_block_step() (boot_cpu_data.x86 >= 6) #endif +struct siginfo; +void arch_fill_sigtrap_info(struct task_struct *tsk, struct pt_regs *regs, + struct siginfo *info); +#define arch_has_fill_sigtrap_info + struct user_desc; extern int do_get_thread_area(struct task_struct *p, int idx, struct user_desc __user *info); --- TH/arch/x86/kernel/ptrace.c~2_CONVERT_X86 2009-09-23 21:12:01.000000000 +0200 +++ TH/arch/x86/kernel/ptrace.c 2009-11-08 20:54:26.000000000 +0100 @@ -1437,21 +1437,33 @@ const struct user_regset_view *task_user #endif } -void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, - int error_code, int si_code) +static inline void fill_sigtrap_info(struct task_struct *tsk, + struct pt_regs *regs, + int error_code, int si_code, + struct siginfo *info) { - struct siginfo info; - tsk->thread.trap_no = 1; tsk->thread.error_code = error_code; - memset(&info, 0, sizeof(info)); - info.si_signo = SIGTRAP; - info.si_code = si_code; + memset(info, 0, sizeof(*info)); + info->si_signo = SIGTRAP; + info->si_code = si_code; + info->si_addr = user_mode_vm(regs) ? (void __user *) regs->ip : NULL; +} - /* User-mode ip? */ - info.si_addr = user_mode_vm(regs) ? (void __user *) regs->ip : NULL; +void arch_fill_sigtrap_info(struct task_struct *tsk, + struct pt_regs *regs, + struct siginfo *info) +{ + fill_sigtrap_info(tsk, regs, 0, TRAP_BRKPT, info); +} +void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, + int error_code, int si_code) +{ + struct siginfo info; + + fill_sigtrap_info(tsk, regs, error_code, si_code, &info); /* Send us the fake SIGTRAP */ force_sig_info(SIGTRAP, &info, tsk); } @@ -1516,29 +1528,22 @@ asmregparm long syscall_trace_enter(stru asmregparm void syscall_trace_leave(struct pt_regs *regs) { + bool step; + if (unlikely(current->audit_context)) audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax); if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_exit(regs, regs->ax); - if (test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall_exit(regs, 0); - /* * If TIF_SYSCALL_EMU is set, we only get here because of * TIF_SINGLESTEP (i.e. this is PTRACE_SYSEMU_SINGLESTEP). * We already reported this syscall instruction in - * syscall_trace_enter(), so don't do any more now. - */ - if (unlikely(test_thread_flag(TIF_SYSCALL_EMU))) - return; - - /* - * If we are single-stepping, synthesize a trap to follow the - * system call instruction. + * syscall_trace_enter(). */ - if (test_thread_flag(TIF_SINGLESTEP) && - tracehook_consider_fatal_signal(current, SIGTRAP)) - send_sigtrap(current, regs, 0, TRAP_BRKPT); + step = unlikely(test_thread_flag(TIF_SINGLESTEP)) && + !test_thread_flag(TIF_SYSCALL_EMU); + if (step || test_thread_flag(TIF_SYSCALL_TRACE)) + tracehook_report_syscall_exit(regs, step); }