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.
This commit is contained in:
parent
1819dce19c
commit
ca843a73b0
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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 @@ 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;
|
||||
|
||||
/*
|
||||
|
|
|
@ -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 @@ 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;
|
||||
|
|
|
@ -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 *);
|
||||
|
|
Loading…
Reference in New Issue