summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkettenis <kettenis@openbsd.org>2012-04-13 16:37:50 +0000
committerkettenis <kettenis@openbsd.org>2012-04-13 16:37:50 +0000
commit4ec195400d023537d947ee6557938900b7cc7161 (patch)
treeae5a44c0389aa411ffbe8060c039ba000dad12a8
parentDon't try to mmap a 0-length file. (diff)
downloadwireguard-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.c6
-rw-r--r--sys/kern/kern_exit.c21
-rw-r--r--sys/kern/kern_fork.c3
-rw-r--r--sys/kern/kern_sig.c16
-rw-r--r--sys/kern/sys_process.c22
-rw-r--r--sys/sys/proc.h4
-rw-r--r--sys/sys/ptrace.h3
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