Module Name: src
Committed By: christos
Date: Tue Apr 6 13:50:22 UTC 2010
Modified Files:
src/lib/libc/sys: ptrace.2
src/sys/kern: kern_lwp.c kern_sig.c sys_process.c
src/sys/sys: lwp.h
Log Message:
PR/43128: Paul Koning: Threads support in ptrace() is insufficient for gdb to
debug threaded live apps: Add an optional lwpid in PT_STEP and PT_CONTINUE to
indicate which lwp to operate on, and implement the glue required to make it
work.
To generate a diff of this commit:
cvs rdiff -u -r1.31 -r1.32 src/lib/libc/sys/ptrace.2
cvs rdiff -u -r1.141 -r1.142 src/sys/kern/kern_lwp.c
cvs rdiff -u -r1.304 -r1.305 src/sys/kern/kern_sig.c
cvs rdiff -u -r1.153 -r1.154 src/sys/kern/sys_process.c
cvs rdiff -u -r1.128 -r1.129 src/sys/sys/lwp.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/lib/libc/sys/ptrace.2
diff -u src/lib/libc/sys/ptrace.2:1.31 src/lib/libc/sys/ptrace.2:1.32
--- src/lib/libc/sys/ptrace.2:1.31 Mon Mar 22 15:30:55 2010
+++ src/lib/libc/sys/ptrace.2 Tue Apr 6 09:50:22 2010
@@ -1,7 +1,7 @@
-.\" $NetBSD: ptrace.2,v 1.31 2010/03/22 19:30:55 joerg Exp $
+.\" $NetBSD: ptrace.2,v 1.32 2010/04/06 13:50:22 christos Exp $
.\"
.\" This file is in the public domain.
-.Dd March 12, 2007
+.Dd April 6, 2010
.Dt PTRACE 2
.Os
.Sh NAME
@@ -149,7 +149,9 @@
to indicate that execution is to pick up where it left off.
.Fa data
provides a signal number to be delivered to the traced process as it
-resumes execution, or 0 if no signal is to be sent.
+resumes execution, or 0 if no signal is to be sent. If a negative
+value is supplied, that is the negative of the LWP ID of the thread to
+be resumed, and only that thread executes.
.It Dv PT_KILL
The traced process terminates, as if
.Dv PT_CONTINUE
@@ -256,8 +258,8 @@
call currently does not stop the child process so it can generate
inconsistent data.
.It Dv PT_LWPINFO
-Returns information about the specific thread from the process specified
-in the
+Returns information about a thread from the list of threads for the
+process specified in the
.Fa pid
argument.
The
@@ -274,8 +276,15 @@
.Pp
where
.Fa pl_lwpid
-contains the thread for which to get info.
+contains a thread LWP ID. Information is returned for the thread
+following the one with the specified ID in the process thread list,
+or for the first thread if
+.Fa pl_lwpid
+is 0.
Upon return
+.Fa pl_lwpid
+contains the LWP ID of the thread that was found, or 0 if there is
+no thread after the one whose LWP ID was supplied in the call.
.Fa pl_event
contains the event that stopped the thread.
Possible
@@ -303,6 +312,14 @@
Execution continues as in request PT_CONTINUE; however
as soon as possible after execution of at least one
instruction, execution stops again.
+If the
+.Fa data
+argument is greater than 0, it contains the LWP ID of the thread to be
+stepped, and any other threads are continued. If the
+.Fa data
+argument is less than zero, it contains the negative of the LWP ID of
+the
+thread to be stepped, and only that thread executes.
.It Dv PT_GETREGS
This request reads the traced process' machine registers into the
.Dq Li "struct reg"
@@ -310,6 +327,10 @@
.In machine/reg.h )
pointed to by
.Fa addr .
+The
+.Fa data
+argument contains the LWP ID of the thread whose registers are to
+be read. If zero is supplied, the first thread of the process is read.
.It Dv PT_SETREGS
This request is the converse of
.Dv PT_GETREGS ;
@@ -319,6 +340,10 @@
.In machine/reg.h )
pointed to by
.Fa addr .
+The
+.Fa data
+argument contains the LWP ID of the thread whose registers are to
+be written. If zero is supplied, the first thread of the process is written.
.It Dv PT_GETFPREGS
This request reads the traced process' floating-point registers into
the
@@ -327,6 +352,11 @@
.In machine/reg.h )
pointed to by
.Fa addr .
+The
+.Fa data
+argument contains the LWP ID of the thread whose registers are to
+be read. If zero is supplied, the first thread of the process is
+read.
.It Dv PT_SETFPREGS
This request is the converse of
.Dv PT_GETFPREGS ;
@@ -336,6 +366,11 @@
.In machine/reg.h )
pointed to by
.Fa addr .
+The
+.Fa data
+argument contains the LWP ID of the thread whose registers are to
+be written. If zero is supplied, the first thread of the process is
+written.
.\" .It Dv PT_SYSCALL
.\" This request is like
.\" .Dv PT_CONTINUE
Index: src/sys/kern/kern_lwp.c
diff -u src/sys/kern/kern_lwp.c:1.141 src/sys/kern/kern_lwp.c:1.142
--- src/sys/kern/kern_lwp.c:1.141 Mon Mar 1 16:10:17 2010
+++ src/sys/kern/kern_lwp.c Tue Apr 6 09:50:22 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_lwp.c,v 1.141 2010/03/01 21:10:17 darran Exp $ */
+/* $NetBSD: kern_lwp.c,v 1.142 2010/04/06 13:50:22 christos Exp $ */
/*-
* Copyright (c) 2001, 2006, 2007, 2008, 2009 The NetBSD Foundation, Inc.
@@ -209,7 +209,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.141 2010/03/01 21:10:17 darran Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.142 2010/04/06 13:50:22 christos Exp $");
#include "opt_ddb.h"
#include "opt_lockdebug.h"
@@ -375,6 +375,44 @@
}
/*
+ * Restart a stopped LWP.
+ *
+ * Must be called with p_lock held, and the LWP NOT locked. Will unlock the
+ * LWP before return.
+ */
+void
+lwp_unstop(struct lwp *l)
+{
+ struct proc *p = l->l_proc;
+
+ KASSERT(mutex_owned(proc_lock));
+ KASSERT(mutex_owned(p->p_lock));
+
+ lwp_lock(l);
+
+ /* If not stopped, then just bail out. */
+ if (l->l_stat != LSSTOP) {
+ lwp_unlock(l);
+ return;
+ }
+
+ p->p_stat = SACTIVE;
+ p->p_sflag &= ~PS_STOPPING;
+
+ if (!p->p_waited)
+ p->p_pptr->p_nstopchild--;
+
+ if (l->l_wchan == NULL) {
+ /* setrunnable() will release the lock. */
+ setrunnable(l);
+ } else {
+ l->l_stat = LSSLEEP;
+ p->p_nrlwps++;
+ lwp_unlock(l);
+ }
+}
+
+/*
* Wait for an LWP within the current process to exit. If 'lid' is
* non-zero, we are waiting for a specific LWP.
*
@@ -1396,11 +1434,25 @@
struct proc *p = l->l_proc;
mutex_enter(p->p_lock);
+ lwp_delref2(l);
+ mutex_exit(p->p_lock);
+}
+
+/*
+ * Remove one reference to an LWP. If this is the last reference,
+ * then we must finalize the LWP's death. The proc mutex is held
+ * on entry.
+ */
+void
+lwp_delref2(struct lwp *l)
+{
+ struct proc *p = l->l_proc;
+
+ KASSERT(mutex_owned(p->p_lock));
KASSERT(l->l_stat != LSZOMB);
KASSERT(l->l_refcnt > 0);
if (--l->l_refcnt == 0)
cv_broadcast(&p->p_lwpcv);
- mutex_exit(p->p_lock);
}
/*
Index: src/sys/kern/kern_sig.c
diff -u src/sys/kern/kern_sig.c:1.304 src/sys/kern/kern_sig.c:1.305
--- src/sys/kern/kern_sig.c:1.304 Tue Mar 2 19:47:31 2010
+++ src/sys/kern/kern_sig.c Tue Apr 6 09:50:22 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_sig.c,v 1.304 2010/03/03 00:47:31 yamt Exp $ */
+/* $NetBSD: kern_sig.c,v 1.305 2010/04/06 13:50:22 christos Exp $ */
/*-
* Copyright (c) 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -66,7 +66,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.304 2010/03/03 00:47:31 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.305 2010/04/06 13:50:22 christos Exp $");
#include "opt_ptrace.h"
#include "opt_compat_sunos.h"
@@ -1725,9 +1725,10 @@
/*
* If we are no longer being traced, or the parent didn't
- * give us a signal, look for more signals.
+ * give us a signal, or we're stopping, look for more signals.
*/
- if ((p->p_slflag & PSL_TRACED) == 0 || p->p_xstat == 0)
+ if ((p->p_slflag & PSL_TRACED) == 0 || p->p_xstat == 0 ||
+ (p->p_sflag & PS_STOPPING) != 0)
return 0;
/*
Index: src/sys/kern/sys_process.c
diff -u src/sys/kern/sys_process.c:1.153 src/sys/kern/sys_process.c:1.154
--- src/sys/kern/sys_process.c:1.153 Wed Dec 16 20:25:10 2009
+++ src/sys/kern/sys_process.c Tue Apr 6 09:50:22 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: sys_process.c,v 1.153 2009/12/17 01:25:10 rmind Exp $ */
+/* $NetBSD: sys_process.c,v 1.154 2010/04/06 13:50:22 christos Exp $ */
/*-
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -118,7 +118,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_process.c,v 1.153 2009/12/17 01:25:10 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_process.c,v 1.154 2010/04/06 13:50:22 christos Exp $");
#include "opt_ptrace.h"
#include "opt_ktrace.h"
@@ -227,7 +227,7 @@
syscallarg(int) data;
} */
struct proc *p = l->l_proc;
- struct lwp *lt;
+ struct lwp *lt, *lt2;
struct proc *t; /* target process */
struct uio uio;
struct iovec iov;
@@ -235,7 +235,8 @@
struct ptrace_lwpinfo pl;
struct vmspace *vm;
int error, write, tmp, req, pheld;
- int signo;
+ int signo = 0;
+ int resume_all;
ksiginfo_t ksi;
char *path;
int len;
@@ -463,6 +464,7 @@
write = 0;
*retval = 0;
tmp = 0;
+ resume_all = 1;
switch (req) {
case PT_TRACE_ME:
@@ -597,6 +599,44 @@
p->p_trace_enabled = trace_is_enabled(p);
/*
+ * Pick up the LWPID, if supplied. There are two cases:
+ * data < 0 : step or continue single thread, lwp = -data
+ * data > 0 in PT_STEP : step this thread, continue others
+ * For operations other than PT_STEP, data > 0 means
+ * data is the signo to deliver to the process.
+ */
+ tmp = SCARG(uap, data);
+ if (tmp >= 0) {
+#ifdef PT_STEP
+ if (req == PT_STEP)
+ signo = 0;
+ else
+#endif
+ {
+ signo = tmp;
+ tmp = 0; /* don't search for LWP */
+ }
+ }
+ else
+ tmp = -tmp;
+
+ if (tmp > 0) {
+ if (req == PT_DETACH) {
+ error = EINVAL;
+ break;
+ }
+ lwp_delref2 (lt);
+ lt = lwp_find(t, tmp);
+ if (lt == NULL) {
+ error = ESRCH;
+ break;
+ }
+ lwp_addref(lt);
+ resume_all = 0;
+ signo = 0;
+ }
+
+ /*
* From the 4.4BSD PRM:
* "The data argument is taken as a signal number and the
* child's execution continues at location addr as if it
@@ -609,7 +649,7 @@
*/
/* Check that the data is a valid signal number or zero. */
- if (SCARG(uap, data) < 0 || SCARG(uap, data) >= NSIG) {
+ if (signo < 0 || signo >= NSIG) {
error = EINVAL;
break;
}
@@ -623,7 +663,17 @@
#ifdef PT_STEP
/*
* Arrange for a single-step, if that's requested and possible.
+ * More precisely, set the single step status as requested for
+ * the requested thread, and clear it for other threads.
*/
+ LIST_FOREACH(lt2, &t->p_lwps, l_sibling) {
+ if (lt != lt2)
+ {
+ lwp_lock(lt2);
+ process_sstep(lt2, 0);
+ lwp_unlock(lt2);
+ }
+ }
error = process_sstep(lt, req == PT_STEP);
if (error)
break;
@@ -640,8 +690,6 @@
/* not being traced any more */
t->p_opptr = NULL;
}
-
- signo = SCARG(uap, data);
sendsig:
/* Finally, deliver the requested signal (or none). */
if (t->p_stat == SSTOP) {
@@ -651,7 +699,10 @@
* an LWP runs to see it.
*/
t->p_xstat = signo;
- proc_unstop(t);
+ if (resume_all)
+ proc_unstop(t);
+ else
+ lwp_unstop(lt);
} else if (signo != 0) {
KSI_INIT_EMPTY(&ksi);
ksi.ksi_signo = signo;
Index: src/sys/sys/lwp.h
diff -u src/sys/sys/lwp.h:1.128 src/sys/sys/lwp.h:1.129
--- src/sys/sys/lwp.h:1.128 Sat Feb 20 21:11:39 2010
+++ src/sys/sys/lwp.h Tue Apr 6 09:50:22 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: lwp.h,v 1.128 2010/02/21 02:11:39 darran Exp $ */
+/* $NetBSD: lwp.h,v 1.129 2010/04/06 13:50:22 christos Exp $ */
/*-
* Copyright (c) 2001, 2006, 2007, 2008, 2009 The NetBSD Foundation, Inc.
@@ -298,6 +298,7 @@
int lwp_trylock(lwp_t *);
void lwp_addref(lwp_t *);
void lwp_delref(lwp_t *);
+void lwp_delref2(lwp_t *);
void lwp_drainrefs(lwp_t *);
bool lwp_alive(lwp_t *);
lwp_t *lwp_find_first(proc_t *);
@@ -307,6 +308,7 @@
void lwpinit(void);
int lwp_wait1(lwp_t *, lwpid_t, lwpid_t *, int);
void lwp_continue(lwp_t *);
+void lwp_unstop(lwp_t *);
void cpu_setfunc(lwp_t *, void (*)(void *), void *);
void startlwp(void *);
void upcallret(lwp_t *);