Implement following commands: PT_CLEARSTEP, PT_SETSTEP, PT_SUSPEND

PT_RESUME, PT_GETNUMLWPS, PT_GETLWPLIST.
This commit is contained in:
David Xu 2004-07-13 07:25:24 +00:00
parent 53dbf30349
commit ef9457becb
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=132089
2 changed files with 117 additions and 12 deletions

View file

@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <sys/ptrace.h>
#include <sys/sx.h>
#include <sys/user.h>
#include <sys/malloc.h>
#include <machine/reg.h>
@ -373,9 +374,10 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
struct thread *td2 = NULL;
struct ptrace_io_desc *piod;
struct ptrace_lwpinfo *pl;
int error, write, tmp;
int error, write, tmp, num;
int proctree_locked = 0;
lwpid_t tid = 0;
lwpid_t tid = 0, *buf;
pid_t saved_pid = pid;
curp = td->td_proc;
@ -485,6 +487,12 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
/* OK */
break;
case PT_CLEARSTEP:
/* Allow thread to clear single step for itself */
if (td->td_tid == tid)
break;
/* FALLTHROUGH */
default:
/* not being traced... */
if ((p->p_flag & P_TRACED) == 0) {
@ -499,7 +507,8 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
}
/* not currently stopped */
if (!P_SHOULDSTOP(p) || (p->p_flag & P_WAITED) == 0) {
if (!P_SHOULDSTOP(p) || p->p_suspcount != p->p_numthreads ||
(p->p_flag & P_WAITED) == 0) {
error = EBUSY;
goto fail;
}
@ -539,6 +548,42 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
data = SIGSTOP;
goto sendsig; /* in PT_CONTINUE below */
case PT_CLEARSTEP:
_PHOLD(p);
error = ptrace_clear_single_step(td2);
_PRELE(p);
if (error)
goto fail;
PROC_UNLOCK(p);
return (0);
case PT_SETSTEP:
_PHOLD(p);
error = ptrace_single_step(td2);
_PRELE(p);
if (error)
goto fail;
PROC_UNLOCK(p);
return (0);
case PT_SUSPEND:
_PHOLD(p);
mtx_lock_spin(&sched_lock);
td2->td_flags |= TDF_DBSUSPEND;
mtx_unlock_spin(&sched_lock);
_PRELE(p);
PROC_UNLOCK(p);
return (0);
case PT_RESUME:
_PHOLD(p);
mtx_lock_spin(&sched_lock);
td2->td_flags &= ~TDF_DBSUSPEND;
mtx_unlock_spin(&sched_lock);
_PRELE(p);
PROC_UNLOCK(p);
return (0);
case PT_STEP:
case PT_CONTINUE:
case PT_TO_SCE:
@ -612,15 +657,32 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
/* deliver or queue signal */
if (P_SHOULDSTOP(p)) {
p->p_xstat = data;
p->p_xlwpid = 0;
p->p_flag &= ~(P_STOPPED_TRACE|P_STOPPED_SIG);
mtx_lock_spin(&sched_lock);
if (saved_pid <= PID_MAX) {
p->p_xthread->td_flags &= ~TDF_XSIG;
p->p_xthread->td_xsig = data;
} else {
td2->td_flags &= ~TDF_XSIG;
td2->td_xsig = data;
}
p->p_xthread = NULL;
if (req == PT_DETACH) {
struct thread *td3;
FOREACH_THREAD_IN_PROC(p, td3)
td->td_flags &= ~TDF_DBSUSPEND;
}
/*
* unsuspend all threads, to not let a thread run,
* you should use PT_SUSPEND to suspend it before
* continuing process.
*/
thread_unsuspend(p);
setrunnable(td2); /* XXXKSE */
/* Need foreach kse in proc, ... make_kse_queued(). */
thread_continued(p);
mtx_unlock_spin(&sched_lock);
} else if (data)
} else if (data) {
psignal(p, data);
}
PROC_UNLOCK(p);
return (0);
@ -739,12 +801,49 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
return (EINVAL);
pl = addr;
_PHOLD(p);
pl->pl_lwpid = p->p_xlwpid;
if (saved_pid <= PID_MAX) {
pl->pl_lwpid = p->p_xthread->td_tid;
pl->pl_event = PL_EVENT_SIGNAL;
} else {
pl->pl_lwpid = td2->td_tid;
if (td2->td_flags & TDF_XSIG)
pl->pl_event = PL_EVENT_SIGNAL;
else
pl->pl_event = 0;
}
_PRELE(p);
PROC_UNLOCK(p);
pl->pl_event = PL_EVENT_SIGNAL;
return (0);
case PT_GETNUMLWPS:
td->td_retval[0] = p->p_numthreads;
PROC_UNLOCK(p);
return (0);
case PT_GETLWPLIST:
if (data <= 0) {
PROC_UNLOCK(p);
return (EINVAL);
}
num = imin(p->p_numthreads, data);
PROC_UNLOCK(p);
buf = malloc(num * sizeof(lwpid_t), M_TEMP, M_WAITOK);
tmp = 0;
PROC_LOCK(p);
mtx_lock_spin(&sched_lock);
FOREACH_THREAD_IN_PROC(p, td2) {
if (tmp >= num)
break;
buf[tmp++] = td2->td_tid;
}
mtx_unlock_spin(&sched_lock);
PROC_UNLOCK(p);
error = copyout(buf, addr, tmp * sizeof(lwpid_t));
free(buf, M_TEMP);
if (!error)
td->td_retval[0] = num;
return (error);
default:
#ifdef __HAVE_PTRACE_MACHDEP
if (req >= PT_FIRSTMACH) {
@ -782,7 +881,7 @@ stopevent(struct proc *p, unsigned int event, unsigned int val)
p->p_step = 1;
do {
p->p_xstat = val;
p->p_xlwpid = 0;
p->p_xthread = NULL;
p->p_stype = event; /* Which event caused the stop? */
wakeup(&p->p_stype); /* Wake up any PIOCWAIT'ing procs */
msleep(&p->p_step, &p->p_mtx, PWAIT, "stopevent", 0);

View file

@ -48,6 +48,12 @@
#define PT_DETACH 11 /* stop tracing a process */
#define PT_IO 12 /* do I/O to/from stopped process. */
#define PT_LWPINFO 13 /* Info about the LWP that stopped. */
#define PT_GETNUMLWPS 14 /* get total number of threads */
#define PT_GETLWPLIST 15 /* get thread list */
#define PT_CLEARSTEP 16 /* turn off single step */
#define PT_SETSTEP 17 /* turn on single step */
#define PT_SUSPEND 18 /* suspend a thread */
#define PT_RESUME 19 /* resume a thread */
#define PT_TO_SCE 20
#define PT_TO_SCX 21
@ -59,8 +65,7 @@
#define PT_SETFPREGS 36 /* set floating-point registers */
#define PT_GETDBREGS 37 /* get debugging registers */
#define PT_SETDBREGS 38 /* set debugging registers */
#define PT_FIRSTMACH 64 /* for machine-specific requests */
#define PT_FIRSTMACH 64 /* for machine-specific requests */
#include <machine/ptrace.h> /* machine-specific requests, if any */
struct ptrace_io_desc {
@ -102,6 +107,7 @@ struct ptrace_lwpinfo {
int ptrace_set_pc(struct thread *_td, unsigned long _addr);
int ptrace_single_step(struct thread *_td);
int ptrace_clear_single_step(struct thread *_td);
#ifdef __HAVE_PTRACE_MACHDEP
int cpu_ptrace(struct thread *_td, int _req, void *_addr, int _data);