diff options
author | 2012-04-13 16:37:50 +0000 | |
---|---|---|
committer | 2012-04-13 16:37:50 +0000 | |
commit | 4ec195400d023537d947ee6557938900b7cc7161 (patch) | |
tree | ae5a44c0389aa411ffbe8060c039ba000dad12a8 | |
parent | Don't try to mmap a 0-length file. (diff) | |
download | wireguard-openbsd-4ec195400d023537d947ee6557938900b7cc7161.tar.xz wireguard-openbsd-4ec195400d023537d947ee6557938900b7cc7161.zip |
First stab at making ptrace(2) usable for debugging multi-threaded programs.
It implements a full-stop model where all threads are stopped before handing
over control to the debugger. Events are reported as before through wait(2);
you will have to call ptrace(PT_GET_PROCESS_STATE, ...) to find out which
thread hit the event. Since this changes the size of struct ptrace_state,
you will have to recompile gdb.
ok guenther@
-rw-r--r-- | sys/kern/kern_exec.c | 6 | ||||
-rw-r--r-- | sys/kern/kern_exit.c | 21 | ||||
-rw-r--r-- | sys/kern/kern_fork.c | 3 | ||||
-rw-r--r-- | sys/kern/kern_sig.c | 16 | ||||
-rw-r--r-- | sys/kern/sys_process.c | 22 | ||||
-rw-r--r-- | sys/sys/proc.h | 4 | ||||
-rw-r--r-- | sys/sys/ptrace.h | 3 |
7 files changed, 54 insertions, 21 deletions
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index c8a202bd463..ebaca46f136 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_exec.c,v 1.128 2012/04/12 10:11:41 mikeb Exp $ */ +/* $OpenBSD: kern_exec.c,v 1.129 2012/04/13 16:37:50 kettenis Exp $ */ /* $NetBSD: kern_exec.c,v 1.75 1996/02/09 18:59:28 christos Exp $ */ /*- @@ -678,7 +678,7 @@ sys_execve(struct proc *p, void *v, register_t *retval) #endif atomic_clearbits_int(&pr->ps_flags, PS_INEXEC); - single_thread_clear(p); + single_thread_clear(p, P_SUSPSIG); #if NSYSTRACE > 0 if (ISSET(p->p_flag, P_SYSTRACE) && @@ -716,7 +716,7 @@ bad: clrflag: #endif atomic_clearbits_int(&pr->ps_flags, PS_INEXEC); - single_thread_clear(p); + single_thread_clear(p, P_SUSPSIG); if (pathbuf != NULL) pool_put(&namei_pool, pathbuf); diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 62f927aefe4..2565844fb74 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_exit.c,v 1.112 2012/04/11 15:28:50 kettenis Exp $ */ +/* $OpenBSD: kern_exit.c,v 1.113 2012/04/13 16:37:51 kettenis Exp $ */ /* $NetBSD: kern_exit.c,v 1.39 1996/04/22 01:38:25 christos Exp $ */ /* @@ -158,6 +158,10 @@ exit1(struct proc *p, int rv, int flags) /* unlink ourselves from the active threads */ TAILQ_REMOVE(&pr->ps_threads, p, p_thr_link); + if (ISSET(p->p_flag, P_SUSPSINGLE)) { + if (--pr->ps_singlecount == 0) + wakeup(&pr->ps_singlecount); + } if ((p->p_flag & P_THREAD) == 0) { /* main thread gotta wait because it has the pid, et al */ while (! TAILQ_EMPTY(&pr->ps_threads)) @@ -487,6 +491,21 @@ loop: proc_finish_wait(q, p); return (0); } + if (pr->ps_flags & PS_TRACED && + (pr->ps_flags & PS_WAITED) == 0 && pr->ps_single && + pr->ps_single->p_stat == SSTOP && + (pr->ps_single->p_flag & P_SUSPSINGLE) == 0) { + atomic_setbits_int(&pr->ps_flags, PS_WAITED); + retval[0] = p->p_pid; + + if (SCARG(uap, status)) { + status = W_STOPCODE(pr->ps_single->p_xstat); + error = copyout(&status, SCARG(uap, status), + sizeof(status)); + } else + error = 0; + return (error); + } if (p->p_stat == SSTOP && (pr->ps_flags & PS_WAITED) == 0 && (p->p_flag & P_SUSPSINGLE) == 0 && diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 62ed83d6e0f..e2771d04022 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_fork.c,v 1.138 2012/04/12 12:33:03 deraadt Exp $ */ +/* $OpenBSD: kern_fork.c,v 1.139 2012/04/13 16:37:51 kettenis Exp $ */ /* $NetBSD: kern_fork.c,v 1.29 1996/02/09 18:59:34 christos Exp $ */ /* @@ -288,6 +288,7 @@ fork1(struct proc *curp, int exitsig, int flags, void *stack, pid_t *tidptr, p->p_stat = SIDL; /* protect against others */ p->p_exitsig = exitsig; p->p_flag = 0; + p->p_xstat = 0; if (flags & FORK_THREAD) { atomic_setbits_int(&p->p_flag, P_THREAD); diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 991744db1d3..c1cb5857ce0 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sig.c,v 1.140 2012/04/12 10:11:41 mikeb Exp $ */ +/* $OpenBSD: kern_sig.c,v 1.141 2012/04/13 16:37:51 kettenis Exp $ */ /* $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $ */ /* @@ -1072,12 +1072,20 @@ issignal(struct proc *p) */ p->p_xstat = signum; + KERNEL_LOCK(); + single_thread_set(p, SINGLE_SUSPEND, 0); + KERNEL_UNLOCK(); + if (dolock) SCHED_LOCK(s); proc_stop(p, 1); if (dolock) SCHED_UNLOCK(s); + KERNEL_LOCK(); + single_thread_clear(p, 0); + KERNEL_UNLOCK(); + /* * If we are no longer being traced, or the parent * didn't give us a signal, look for more signals. @@ -1766,7 +1774,7 @@ single_thread_set(struct proc *p, enum single_thread_mode mode, int deep) TAILQ_FOREACH(q, &pr->ps_threads, p_thr_link) { int s; - if (q == p) + if (q == p || ISSET(q->p_flag, P_WEXIT)) continue; SCHED_LOCK(s); atomic_setbits_int(&q->p_flag, P_SUSPSINGLE); @@ -1812,7 +1820,7 @@ single_thread_set(struct proc *p, enum single_thread_mode mode, int deep) } void -single_thread_clear(struct proc *p) +single_thread_clear(struct proc *p, int flag) { struct process *pr = p->p_p; struct proc *q; @@ -1834,7 +1842,7 @@ single_thread_clear(struct proc *p) * it back into some sleep queue */ SCHED_LOCK(s); - if (q->p_stat == SSTOP && (q->p_flag & P_SUSPSIG) == 0) { + if (q->p_stat == SSTOP && (q->p_flag & flag) == 0) { if (q->p_wchan == 0) setrunnable(q); else diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index 480f42dd0e3..14a19211c0a 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sys_process.c,v 1.55 2012/04/12 14:40:41 kettenis Exp $ */ +/* $OpenBSD: sys_process.c,v 1.56 2012/04/13 16:37:51 kettenis Exp $ */ /* $NetBSD: sys_process.c,v 1.55 1996/05/15 06:17:47 tls Exp $ */ /*- @@ -84,7 +84,6 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) } */ *uap = v; struct proc *t; /* target thread */ struct process *tr; /* target process */ - struct proc *q; struct uio uio; struct iovec iov; struct ptrace_io_desc piod; @@ -437,6 +436,9 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) * from where it stopped." */ + if (SCARG(uap, pid) < THREAD_PID_OFFSET && tr->ps_single) + t = tr->ps_single; + /* Check that the data is a valid signal number or zero. */ if (SCARG(uap, data) < 0 || SCARG(uap, data) >= NSIG) return (EINVAL); @@ -469,6 +471,9 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) * from where it stopped." */ + if (SCARG(uap, pid) < THREAD_PID_OFFSET && tr->ps_single) + t = tr->ps_single; + /* Check that the data is a valid signal number or zero. */ if (SCARG(uap, data) < 0 || SCARG(uap, data) >= NSIG) return (EINVAL); @@ -507,13 +512,7 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) if (SCARG(uap, data) != 0) psignal(t, SCARG(uap, data)); } - SCHED_LOCK(s); - TAILQ_FOREACH(q, &tr->ps_threads, p_thr_link) { - if (q != t && q->p_stat == SSTOP) { - setrunnable(q); - } - } - SCHED_UNLOCK(s); + return (0); relebad: @@ -561,6 +560,11 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) case PT_GET_PROCESS_STATE: if (SCARG(uap, data) != sizeof(*tr->ps_ptstat)) return (EINVAL); + + if (tr->ps_single) + tr->ps_ptstat->pe_tid = + tr->ps_single->p_pid + THREAD_PID_OFFSET; + return (copyout(tr->ps_ptstat, SCARG(uap, addr), sizeof(*tr->ps_ptstat))); diff --git a/sys/sys/proc.h b/sys/sys/proc.h index e882c276629..d3ed87cff35 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: proc.h,v 1.157 2012/04/12 12:33:03 deraadt Exp $ */ +/* $OpenBSD: proc.h,v 1.158 2012/04/13 16:37:50 kettenis Exp $ */ /* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */ /*- @@ -545,7 +545,7 @@ enum single_thread_mode { SINGLE_EXIT /* other threads to unwind and then exit */ }; int single_thread_set(struct proc *, enum single_thread_mode, int); -void single_thread_clear(struct proc *); +void single_thread_clear(struct proc *, int); int single_thread_check(struct proc *, int); void child_return(void *); diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h index d29b03bcb22..3c8fda30f21 100644 --- a/sys/sys/ptrace.h +++ b/sys/sys/ptrace.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ptrace.h,v 1.13 2012/02/20 22:23:39 guenther Exp $ */ +/* $OpenBSD: ptrace.h,v 1.14 2012/04/13 16:37:50 kettenis Exp $ */ /* $NetBSD: ptrace.h,v 1.21 1996/02/09 18:25:26 christos Exp $ */ /*- @@ -76,6 +76,7 @@ typedef struct ptrace_event { typedef struct ptrace_state { int pe_report_event; pid_t pe_other_pid; + pid_t pe_tid; } ptrace_state_t; #define PT_GET_THREAD_FIRST 15 |