From: Roland McGrath On x86 and x86-64, setting up to run a signal handler clears the single-step bit (TF) in the processor flags before starting the handler. This makes sense when a process is handling its own SIGTRAPs. But when TF is set because PTRACE_SINGLESTEP was used, and that call specified a handled signal so the handler setup is happening, it doesn't make so much sense. When the debugger stops to show you a signal about to be delivered, and that signal should be handled, and then you do step or stepi, you expect to see the signal handler code. In fact, the signal handler runs to completion and then you see the single-step trap at the resumed code instead of seeing the handler. This patch changes signal handler setup so that when TF is set and the thread is under ptrace control, it synthesizes a single-step trap after setting up the PC and registers to start the handler. This makes that PTRACE_SINGLESTEP not strictly a "step", since it actually runs no user instructions at all. But it is definitely what a debugger user wants, so that single-stepping always stops and shows each and every instruction before it gets executed. Signed-off-by: Roland McGrath Signed-off-by: Andrew Morton --- 25-akpm/arch/i386/kernel/signal.c | 17 +++++++++++++++-- 25-akpm/arch/x86_64/ia32/ia32_signal.c | 16 ++++++++++++++-- 25-akpm/arch/x86_64/kernel/signal.c | 8 +++++++- 3 files changed, 36 insertions(+), 5 deletions(-) diff -puN arch/i386/kernel/signal.c~make-single-step-into-signal-delivery-stop-in-handler arch/i386/kernel/signal.c --- 25/arch/i386/kernel/signal.c~make-single-step-into-signal-delivery-stop-in-handler 2004-08-30 21:47:08.015963024 -0700 +++ 25-akpm/arch/i386/kernel/signal.c 2004-08-30 21:47:08.024961656 -0700 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -406,7 +407,13 @@ static void setup_frame(int sig, struct regs->xes = __USER_DS; regs->xss = __USER_DS; regs->xcs = __USER_CS; - regs->eflags &= ~TF_MASK; + if (regs->eflags & TF_MASK) { + if (current->ptrace & PT_PTRACED) { + ptrace_notify(SIGTRAP); + } else { + regs->eflags &= ~TF_MASK; + } + } #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", @@ -490,7 +497,13 @@ static void setup_rt_frame(int sig, stru regs->xes = __USER_DS; regs->xss = __USER_DS; regs->xcs = __USER_CS; - regs->eflags &= ~TF_MASK; + if (regs->eflags & TF_MASK) { + if (current->ptrace & PT_PTRACED) { + ptrace_notify(SIGTRAP); + } else { + regs->eflags &= ~TF_MASK; + } + } #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", diff -puN arch/x86_64/ia32/ia32_signal.c~make-single-step-into-signal-delivery-stop-in-handler arch/x86_64/ia32/ia32_signal.c --- 25/arch/x86_64/ia32/ia32_signal.c~make-single-step-into-signal-delivery-stop-in-handler 2004-08-30 21:47:08.017962720 -0700 +++ 25-akpm/arch/x86_64/ia32/ia32_signal.c 2004-08-30 21:47:08.025961504 -0700 @@ -491,7 +491,13 @@ void ia32_setup_frame(int sig, struct k_ regs->ss = __USER32_DS; set_fs(USER_DS); - regs->eflags &= ~TF_MASK; + if (regs->eflags & TF_MASK) { + if (current->ptrace & PT_PTRACED) { + ptrace_notify(SIGTRAP); + } else { + regs->eflags &= ~TF_MASK; + } + } #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", @@ -585,7 +591,13 @@ void ia32_setup_rt_frame(int sig, struct regs->ss = __USER32_DS; set_fs(USER_DS); - regs->eflags &= ~TF_MASK; + if (regs->eflags & TF_MASK) { + if (current->ptrace & PT_PTRACED) { + ptrace_notify(SIGTRAP); + } else { + regs->eflags &= ~TF_MASK; + } + } #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", diff -puN arch/x86_64/kernel/signal.c~make-single-step-into-signal-delivery-stop-in-handler arch/x86_64/kernel/signal.c --- 25/arch/x86_64/kernel/signal.c~make-single-step-into-signal-delivery-stop-in-handler 2004-08-30 21:47:08.019962416 -0700 +++ 25-akpm/arch/x86_64/kernel/signal.c 2004-08-30 21:47:08.025961504 -0700 @@ -319,7 +319,13 @@ static void setup_rt_frame(int sig, stru regs->rsp = (unsigned long)frame; set_fs(USER_DS); - regs->eflags &= ~TF_MASK; + if (regs->eflags & TF_MASK) { + if (current->ptrace & PT_PTRACED) { + ptrace_notify(SIGTRAP); + } else { + regs->eflags &= ~TF_MASK; + } + } #ifdef DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", _