Index: sys/amd64/amd64/machdep.c =================================================================== --- sys/amd64/amd64/machdep.c +++ sys/amd64/amd64/machdep.c @@ -1960,15 +1960,26 @@ } int -ptrace_single_step(struct thread *td) +ptrace_single_step(struct thread *td, bool onetime) { - td->td_frame->tf_rflags |= PSL_T; + bool t_set; + + t_set = (td->td_frame->tf_rflags & PSL_T) != 0; + if (!t_set) { + td->td_frame->tf_rflags |= PSL_T; + if (onetime) { + PROC_LOCK(td->td_proc); + td->td_dbgflags |= TDB_STEP; + PROC_UNLOCK(td->td_proc); + } + } return (0); } int ptrace_clear_single_step(struct thread *td) { + td->td_frame->tf_rflags &= ~PSL_T; return (0); } Index: sys/amd64/amd64/trap.c =================================================================== --- sys/amd64/amd64/trap.c +++ sys/amd64/amd64/trap.c @@ -266,19 +266,27 @@ ucode = ILL_PRVOPC; break; - case T_BPTFLT: /* bpt instruction fault */ case T_TRCTRAP: /* trace trap */ enable_intr(); -#ifdef KDTRACE_HOOKS - if (type == T_BPTFLT) { - if (dtrace_pid_probe_ptr != NULL && - dtrace_pid_probe_ptr(frame) == 0) - return; + PROC_LOCK(td->td_proc); + if ((td->td_dbgflags & TDB_STEP) != 0) { + td->td_frame->tf_rflags &= ~PSL_T; + td->td_dbgflags &= ~TDB_STEP; } + PROC_UNLOCK(td->td_proc); + ucode = TRAP_TRACE; + signo = SIGTRAP; + break; + + case T_BPTFLT: /* bpt instruction fault */ + enable_intr(); +#ifdef KDTRACE_HOOKS + if (dtrace_pid_probe_ptr != NULL && + dtrace_pid_probe_ptr(frame) == 0) + return; #endif - frame->tf_rflags &= ~PSL_T; + ucode = TRAP_BRKPT; signo = SIGTRAP; - ucode = (type == T_TRCTRAP ? TRAP_TRACE : TRAP_BRKPT); break; case T_ARITHTRAP: /* arithmetic trap */ Index: sys/i386/i386/machdep.c =================================================================== --- sys/i386/i386/machdep.c +++ sys/i386/i386/machdep.c @@ -2769,15 +2769,26 @@ } int -ptrace_single_step(struct thread *td) +ptrace_single_step(struct thread *td, bool onetime) { - td->td_frame->tf_eflags |= PSL_T; + bool t_set; + + t_set = (td->td_frame->tf_eflags & PSL_T) != 0; + if (!t_set) { + td->td_frame->tf_eflags |= PSL_T; + if (onetime) { + PROC_LOCK(td->td_proc); + td->td_dbgflags |= TDB_STEP; + PROC_UNLOCK(td->td_proc); + } + } return (0); } int ptrace_clear_single_step(struct thread *td) { + td->td_frame->tf_eflags &= ~PSL_T; return (0); } Index: sys/i386/i386/trap.c =================================================================== --- sys/i386/i386/trap.c +++ sys/i386/i386/trap.c @@ -320,20 +320,28 @@ ucode = ILL_PRVOPC; break; - case T_BPTFLT: /* bpt instruction fault */ case T_TRCTRAP: /* trace trap */ enable_intr(); -#ifdef KDTRACE_HOOKS - if (type == T_BPTFLT) { - if (dtrace_pid_probe_ptr != NULL && - dtrace_pid_probe_ptr(frame) == 0) - return; + PROC_LOCK(td->td_proc); + if ((td->td_dbgflags & TDB_STEP) != 0) { + td->td_frame->tf_eflags &= ~PSL_T; + td->td_dbgflags &= ~TDB_STEP; } -#endif + PROC_UNLOCK(td->td_proc); user_trctrap_out: - frame->tf_eflags &= ~PSL_T; signo = SIGTRAP; - ucode = (type == T_TRCTRAP ? TRAP_TRACE : TRAP_BRKPT); + ucode = TRAP_TRACE; + break; + + case T_BPTFLT: /* bpt instruction fault */ + enable_intr(); +#ifdef KDTRACE_HOOKS + if (dtrace_pid_probe_ptr != NULL && + dtrace_pid_probe_ptr(frame) == 0) + return; +#endif + signo = SIGTRAP; + ucode = TRAP_BRKPT; break; case T_ARITHTRAP: /* arithmetic trap */ @@ -352,7 +360,6 @@ if (frame->tf_eflags & PSL_VM) { signo = vm86_emulate((struct vm86frame *)frame); if (signo == SIGTRAP) { - type = T_TRCTRAP; load_dr6(rdr6() | 0x4000); goto user_trctrap_out; } Index: sys/kern/sys_process.c =================================================================== --- sys/kern/sys_process.c +++ sys/kern/sys_process.c @@ -221,7 +221,7 @@ proc_sstep(struct thread *td) { - PROC_ACTION(ptrace_single_step(td)); + PROC_ACTION(ptrace_single_step(td, true)); } int @@ -951,7 +951,7 @@ case PT_SETSTEP: CTR2(KTR_PTRACE, "PT_SETSTEP: tid %d (pid %d)", td2->td_tid, p->p_pid); - error = ptrace_single_step(td2); + error = ptrace_single_step(td2, false); break; case PT_SUSPEND: @@ -1053,7 +1053,7 @@ case PT_STEP: CTR3(KTR_PTRACE, "PT_STEP: tid %d (pid %d), sig = %d", td2->td_tid, p->p_pid, data); - error = ptrace_single_step(td2); + error = ptrace_single_step(td2, true); if (error) goto out; break; Index: sys/sys/proc.h =================================================================== --- sys/sys/proc.h +++ sys/sys/proc.h @@ -445,6 +445,7 @@ #define TDB_EXIT 0x00000400 /* Exiting LWP indicator for ptrace() */ #define TDB_VFORK 0x00000800 /* vfork indicator for ptrace() */ #define TDB_FSTP 0x00001000 /* The thread is PT_ATTACH leader */ +#define TDB_STEP 0x00002000 /* (x86) PSL_T set for PT_STEP */ /* * "Private" flags kept in td_pflags: Index: sys/sys/ptrace.h =================================================================== --- sys/sys/ptrace.h +++ sys/sys/ptrace.h @@ -172,7 +172,7 @@ #ifdef _KERNEL int ptrace_set_pc(struct thread *_td, unsigned long _addr); -int ptrace_single_step(struct thread *_td); +int ptrace_single_step(struct thread *_td, bool onetime); int ptrace_clear_single_step(struct thread *_td); #ifdef __HAVE_PTRACE_MACHDEP