Thanks Roland. But now I am even more confused...
On 09/20, Roland McGrath wrote: > > > - PTRACE_SINGLESTEP does user_enable_single_step() > > > > - when the tracee returns to user mode, the next instruction > > causes exception, do_debug()->send_sigtrap() sends SIGTRAP > > > > - the tracee notices the signal and reports this SIGTRAP > > Correct. But if the tracee is inside the syscall path at the time, then > it's a little different. TIF_SINGLESTEP being set means it will go to the > syscall_trace_leave path and send a signal before it actually returns to > user mode. I am not sure... I can hardly read entry_64.S, but I am not sure system_call_fastpath: path calls syscall_trace_leave() on exit... OK, I added printk to syscall_trace_leave(), please see below. > > At least. Is it true that X86_EFLAGS_TF should provoke the > > exception/do_debug? > > Yes. You can even set it yourself in userland with: > > pushf > orl $0x100, (%rsp) /* or (%esp) */ > popf > > and see the signal. Yes, this works. > > But, whatever I did this doesn't work. So, what user_enable_single_step() > > actually means? > > It works very well in the vanilla kernel > ... > I tried your prctl hack on the vanilla kernel and a test program does > indeed get a SIGTRAP. (This is an x86_64 kernel on an Intel chip, trying > both 32-bit and 64-bit test programs.) I used the vanilla kernel too. It doesn't work for me. Under KVM at least... OK, the kernel patch: --- TTT/kernel/sys.c~TF_FBG 2009-06-17 14:11:26.000000000 +0200 +++ TTT/kernel/sys.c 2009-09-21 20:03:27.000000000 +0200 @@ -1428,6 +1428,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsi error = 0; switch (option) { + case 666: + printk(KERN_INFO "prctl: before=%lX\n", task_pt_regs(current)->flags); + user_enable_single_step(current); + printk(KERN_INFO "prctl: after=%lX\n", task_pt_regs(current)->flags); + break; + case PR_SET_PDEATHSIG: if (!valid_signal(arg2)) { error = -EINVAL; --- TTT/arch/x86/kernel/ptrace.c~TF_FBG 2009-06-11 14:16:46.000000000 +0200 +++ TTT/arch/x86/kernel/ptrace.c 2009-09-21 20:22:52.000000000 +0200 @@ -1520,6 +1520,8 @@ asmregparm long syscall_trace_enter(stru asmregparm void syscall_trace_leave(struct pt_regs *regs) { + printk(KERN_INFO "trace_leave enter\n"); + if (unlikely(current->audit_context)) audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax); @@ -1543,6 +1545,8 @@ asmregparm void syscall_trace_leave(stru * system call instruction. */ if (test_thread_flag(TIF_SINGLESTEP) && - tracehook_consider_fatal_signal(current, SIGTRAP)) + tracehook_consider_fatal_signal(current, SIGTRAP)) { + printk(KERN_INFO "trace_leave sends SIGTRAP\n"); send_sigtrap(current, regs, 0, TRAP_BRKPT); + } } version: $ uname -a Linux myhost 2.6.31-00008-g41b61a1-dirty #2 SMP PREEMPT Mon Sep 21 20:23:05 CEST 2009 x86_64 QEMU Virtual CPU version 0.9.1 GenuineIntel GNU/Linux The 1ts test: int main(void) { assert(0 == prctl(666)); for (;;) ; return 0; } it doesn't get SIGTRAP, and syscall_trace_leave() is not called. $ dmesg -c prctl: before=10246 prctl: after=10346 The same for this test: int main(void) { assert(0 == prctl(666)); pause(); return 0; } However, int main(void) { assert(0 == prctl(666)); printf("after prctl\n"); return 0; } dies with "Trace/breakpoint trap", dmesg says: prctl: before=10246 prctl: after=10346 trace_leave enter I guess "trace_leave enter" corresponds to the next syscall, not to prtcl(). This test int main(void) { printf("before prctl\n"); assert(0 == prctl(666)); printf("after prctl\n"); return 0; } gets SIGTRAP too, but printf() succeeds: before prctl after prctl Trace/breakpoint trap The final test-case: static inline unsigned long getflags(void) { unsigned long flags; asm volatile("pushf ; pop %0\n" : "=rm" (flags) : /* no input */ : "memory"); return flags; } int main(void) { unsigned long flags; printf("user_enable_single_step()...\n"); assert(0 == prctl(666)); flags = getflags(); printf("flags=%lX\n", flags); for (;;) ; return 0; } Result: user_enable_single_step()... flags=246 Trace/breakpoint trap dmesg is the same: prctl: before=10246 prctl: after=10346 trace_leave enter Oleg.