Index: sys/arch/amd64/include/ptrace.h =================================================================== RCS file: /cvsroot/src/sys/arch/amd64/include/ptrace.h,v retrieving revision 1.10 diff -u -r1.10 ptrace.h --- sys/arch/amd64/include/ptrace.h 23 Feb 2017 03:34:22 -0000 1.10 +++ sys/arch/amd64/include/ptrace.h 5 Apr 2017 21:50:52 -0000 @@ -43,6 +43,8 @@ #define PT_SETFPREGS (PT_FIRSTMACH + 4) #define PT_GETDBREGS (PT_FIRSTMACH + 5) #define PT_SETDBREGS (PT_FIRSTMACH + 6) +#define PT_SETSTEP (PT_FIRSTMACH + 7) +#define PT_CLEARSTEP (PT_FIRSTMACH + 8) #define PT_MACHDEP_STRINGS \ "PT_STEP", \ @@ -51,7 +53,8 @@ "PT_GETFPREGS", \ "PT_SETFPREGS", \ "PT_GETDBREGS", \ - "PT_SETDBREGS", + "PT_SETSTEP", \ + "PT_CLEARSTEP", #include #define PTRACE_REG_PC(r) (r)->regs[_REG_RIP] Index: sys/kern/sys_ptrace_common.c =================================================================== RCS file: /cvsroot/src/sys/kern/sys_ptrace_common.c,v retrieving revision 1.20 diff -u -r1.20 sys_ptrace_common.c --- sys/kern/sys_ptrace_common.c 29 Mar 2017 22:48:03 -0000 1.20 +++ sys/kern/sys_ptrace_common.c 5 Apr 2017 21:51:22 -0000 @@ -229,6 +229,8 @@ #ifdef PT_STEP case PT_STEP: + case PT_SETSTEP: + case PT_CLEARSTEP: #endif case PT_CONTINUE: case PT_KILL: @@ -452,6 +454,8 @@ case PT_DUMPCORE: #ifdef PT_STEP case PT_STEP: + case PT_SETSTEP: + case PT_CLEARSTEP: #endif case PT_SET_EVENT_MASK: case PT_GET_EVENT_MASK: @@ -532,6 +536,8 @@ switch (req) { #ifdef PT_STEP case PT_STEP: + case PT_SETSTEP: + case PT_CLEARSTEP: #endif case PT_CONTINUE: case PT_DETACH: @@ -797,13 +803,18 @@ * the requested thread, and clear it for other threads. */ LIST_FOREACH(lt2, &t->p_lwps, l_sibling) { - if (lt != lt2) { + if (ISSET(lt2->l_pflag, LP_SINGLESTEP)) { + lwp_lock(lt2); + process_sstep(lt2, 1); + lwp_unlock(lt2); + } else if (lt != lt2) { lwp_lock(lt2); process_sstep(lt2, 0); lwp_unlock(lt2); } } - error = process_sstep(lt, req == PT_STEP); + error = process_sstep(lt, + ISSET(lt->l_pflag, LP_SINGLESTEP) || req == PT_STEP); if (error) break; #endif @@ -818,6 +829,12 @@ /* not being traced any more */ t->p_opptr = NULL; + + /* clear single step */ + LIST_FOREACH(lt2, &t->p_lwps, l_sibling) { + CLR(lt2->l_pflag, LP_SINGLESTEP); + } + CLR(lt->l_pflag, LP_SINGLESTEP); } sendsig: t->p_fpid = 0; @@ -862,6 +879,36 @@ SET(t->p_slflag, PSL_SYSCALLEMU); break; +#ifdef PT_STEP + case PT_SETSTEP: + write = 1; + + case PT_CLEARSTEP: + /* write = 0 done above. */ + + tmp = data; + if (tmp != 0 && t->p_nlwps > 1) { + lwp_delref(lt); + mutex_enter(t->p_lock); + lt = lwp_find(t, tmp); + if (lt == NULL) { + mutex_exit(t->p_lock); + error = ESRCH; + break; + } + lwp_addref(lt); + mutex_exit(t->p_lock); + } + + if (ISSET(lt->l_flag, LW_SYSTEM)) + error = EINVAL; + else if (write) + SET(lt->l_pflag, LP_SINGLESTEP); + else + CLR(lt->l_pflag, LP_SINGLESTEP); + break; +#endif + case PT_KILL: /* just send the process a KILL signal. */ signo = SIGKILL; Index: sys/sys/lwp.h =================================================================== RCS file: /cvsroot/src/sys/sys/lwp.h,v retrieving revision 1.172 diff -u -r1.172 lwp.h --- sys/sys/lwp.h 3 Jul 2016 14:24:59 -0000 1.172 +++ sys/sys/lwp.h 5 Apr 2017 21:51:22 -0000 @@ -255,6 +255,7 @@ #define LP_SYSCTLWRITE 0x00000080 /* sysctl write lock held */ #define LP_MUSTJOIN 0x00000100 /* Must join kthread on exit */ #define LP_VFORKWAIT 0x00000200 /* Waiting at vfork() for a child */ +#define LP_SINGLESTEP 0x00000400 /* Single step thread in ptrace(2) */ #define LP_TIMEINTR 0x00010000 /* Time this soft interrupt */ #define LP_RUNNING 0x20000000 /* Active on a CPU */ #define LP_BOUND 0x80000000 /* Bound to a CPU */ Index: tests/lib/libc/sys/t_ptrace_wait.c =================================================================== RCS file: /cvsroot/src/tests/lib/libc/sys/t_ptrace_wait.c,v retrieving revision 1.1 diff -u -r1.1 t_ptrace_wait.c --- tests/lib/libc/sys/t_ptrace_wait.c 2 Apr 2017 21:44:00 -0000 1.1 +++ tests/lib/libc/sys/t_ptrace_wait.c 5 Apr 2017 21:51:23 -0000 @@ -4396,7 +4396,7 @@ #if defined(PT_STEP) static void -ptrace_step(int N) +ptrace_step(int N, int setstep) { const int exitval = 5; const int sigval = SIGSTOP; @@ -4435,15 +4435,32 @@ validate_status_stopped(status, sigval); while (N --> 0) { - printf("Before resuming the child process where it left off " - "and without signal to be sent (use PT_STEP)\n"); - ATF_REQUIRE(ptrace(PT_STEP, child, (void *)1, 0) != -1); + if (setstep) { + printf("Before resuming the child process where it " + "left off and without signal to be sent (use " + "PT_STEP)\n"); + ATF_REQUIRE(ptrace(PT_SETSTEP, child, (void *)1, 0) + != -1); + ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) + != -1); + } else { + printf("Before resuming the child process where it " + "left off and without signal to be sent (use " + "PT_STEP)\n"); + ATF_REQUIRE(ptrace(PT_STEP, child, (void *)1, 0) + != -1); + } printf("Before calling %s() for the child\n", TWAIT_FNAME); TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); validate_status_stopped(status, SIGTRAP); + + if (setstep) { + ATF_REQUIRE(ptrace(PT_CLEARSTEP, child, (void *)1, 0) + != -1); + } } printf("Before resuming the child process where it left off and " @@ -4470,7 +4487,7 @@ ATF_TC_BODY(step1, tc) { - ptrace_step(1); + ptrace_step(1, 0); } #endif @@ -4484,7 +4501,7 @@ ATF_TC_BODY(step2, tc) { - ptrace_step(2); + ptrace_step(2, 0); } #endif @@ -4498,7 +4515,7 @@ ATF_TC_BODY(step3, tc) { - ptrace_step(3); + ptrace_step(3, 0); } #endif @@ -4512,7 +4529,63 @@ ATF_TC_BODY(step4, tc) { - ptrace_step(3); + ptrace_step(4, 0); +} +#endif + +#if defined(PT_STEP) +ATF_TC(setstep1); +ATF_TC_HEAD(setstep1, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify single PT_SETSTEP call"); +} + +ATF_TC_BODY(setstep1, tc) +{ + ptrace_step(1, 1); +} +#endif + +#if defined(PT_STEP) +ATF_TC(setstep2); +ATF_TC_HEAD(setstep2, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify PT_SETSTEP called twice"); +} + +ATF_TC_BODY(setstep2, tc) +{ + ptrace_step(2, 1); +} +#endif + +#if defined(PT_STEP) +ATF_TC(setstep3); +ATF_TC_HEAD(setstep3, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify PT_SETSTEP called three times"); +} + +ATF_TC_BODY(setstep3, tc) +{ + ptrace_step(3, 1); +} +#endif + +#if defined(PT_STEP) +ATF_TC(setstep4); +ATF_TC_HEAD(setstep4, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify PT_SETSTEP called four times"); +} + +ATF_TC_BODY(setstep4, tc) +{ + ptrace_step(4, 1); } #endif @@ -7535,6 +7608,11 @@ ATF_TP_ADD_TC_PT_STEP(tp, step3); ATF_TP_ADD_TC_PT_STEP(tp, step4); + ATF_TP_ADD_TC_PT_STEP(tp, setstep1); + ATF_TP_ADD_TC_PT_STEP(tp, setstep2); + ATF_TP_ADD_TC_PT_STEP(tp, setstep3); + ATF_TP_ADD_TC_PT_STEP(tp, setstep4); + ATF_TP_ADD_TC(tp, kill1); ATF_TP_ADD_TC(tp, kill2);