diff --git a/lib/libc/sys/ptrace.2 b/lib/libc/sys/ptrace.2 index 63d412d48477..4f129a8386df 100644 --- a/lib/libc/sys/ptrace.2 +++ b/lib/libc/sys/ptrace.2 @@ -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 @@ new value for the program counter), or 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 @@ This 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 @@ struct ptrace_lwpinfo { .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 @@ lists which requests exist on a given machine. 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 @@ This request reads the traced process' machine registers into the .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 @@ it loads the traced process' machine registers from the .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 @@ the .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 @@ it loads the traced process' floating-point registers from the .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 diff --git a/sys/kern/kern_lwp.c b/sys/kern/kern_lwp.c index c6bce17a4e7b..0664177ccd0e 100644 --- a/sys/kern/kern_lwp.c +++ b/sys/kern/kern_lwp.c @@ -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 -__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" @@ -374,6 +374,44 @@ lwp_continue(struct lwp *l) setrunnable(l); } +/* + * 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 @@ lwp_delref(struct lwp *l) 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); } /* diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 97876e2958e7..5a490063b791 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -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 -__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 @@ sigchecktrace(void) /* * 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; /* diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index e74b5bb86323..3e0e683e96d6 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -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 -__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 @@ sys_ptrace(struct lwp *l, const struct sys_ptrace_args *uap, register_t *retval) 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 @@ sys_ptrace(struct lwp *l, const struct sys_ptrace_args *uap, register_t *retval) 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 @@ sys_ptrace(struct lwp *l, const struct sys_ptrace_args *uap, register_t *retval) write = 0; *retval = 0; tmp = 0; + resume_all = 1; switch (req) { case PT_TRACE_ME: @@ -596,6 +598,44 @@ sys_ptrace(struct lwp *l, const struct sys_ptrace_args *uap, register_t *retval) } 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 @@ -609,7 +649,7 @@ sys_ptrace(struct lwp *l, const struct sys_ptrace_args *uap, register_t *retval) */ /* 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 @@ sys_ptrace(struct lwp *l, const struct sys_ptrace_args *uap, register_t *retval) #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 @@ sys_ptrace(struct lwp *l, const struct sys_ptrace_args *uap, register_t *retval) /* 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 @@ sys_ptrace(struct lwp *l, const struct sys_ptrace_args *uap, register_t *retval) * 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; diff --git a/sys/sys/lwp.h b/sys/sys/lwp.h index df11ebeb7056..ed502f967a12 100644 --- a/sys/sys/lwp.h +++ b/sys/sys/lwp.h @@ -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 @@ void lwp_relock(lwp_t *, kmutex_t *); 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 @@ lwp_t *lwp_find_first(proc_t *); 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 *);