* Use FreeBSD's process library instead of the Solaris one.

* There are a few placeholders in here for which there isn't libproc
  support code yet. This is relevent to userland tracing. This set of
  commits is designed to get kernel tracing up and running, with the
  userland stuff to follow later.
This commit is contained in:
John Birrell 2008-04-26 04:51:45 +00:00
parent d46d190310
commit bbda5851ce
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=178565

View File

@ -79,7 +79,9 @@
*/
#include <sys/wait.h>
#if defined(sun)
#include <sys/lwp.h>
#endif
#include <strings.h>
#include <signal.h>
#include <assert.h>
@ -93,6 +95,7 @@
#define IS_SYS_FORK(w) (w == SYS_vfork || w == SYS_fork1 || \
w == SYS_forkall || w == SYS_forksys)
#ifdef DOODAD
static dt_bkpt_t *
dt_proc_bpcreate(dt_proc_t *dpr, uintptr_t addr, dt_bkpt_f *func, void *data)
{
@ -114,27 +117,36 @@ dt_proc_bpcreate(dt_proc_t *dpr, uintptr_t addr, dt_bkpt_f *func, void *data)
return (dbp);
}
#endif
static void
dt_proc_bpdestroy(dt_proc_t *dpr, int delbkpts)
{
#if defined(sun)
int state = Pstate(dpr->dpr_proc);
#else
int state = proc_state(dpr->dpr_proc);
#endif
dt_bkpt_t *dbp, *nbp;
assert(DT_MUTEX_HELD(&dpr->dpr_lock));
for (dbp = dt_list_next(&dpr->dpr_bps); dbp != NULL; dbp = nbp) {
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#ifdef DOODAD
if (delbkpts && dbp->dbp_active &&
state != PS_LOST && state != PS_UNDEAD) {
(void) Pdelbkpt(dpr->dpr_proc,
dbp->dbp_addr, dbp->dbp_instr);
}
#endif
nbp = dt_list_next(dbp);
dt_list_delete(&dpr->dpr_bps, dbp);
dt_free(dpr->dpr_hdl, dbp);
}
}
#ifdef DOODAD
static void
dt_proc_bpmatch(dtrace_hdl_t *dtp, dt_proc_t *dpr)
{
@ -161,6 +173,7 @@ dt_proc_bpmatch(dtrace_hdl_t *dtp, dt_proc_t *dpr)
dbp->dbp_func(dtp, dpr, dbp->dbp_data);
(void) Pxecbkpt(dpr->dpr_proc, dbp->dbp_instr);
}
#endif
static void
dt_proc_bpenable(dt_proc_t *dpr)
@ -171,9 +184,12 @@ dt_proc_bpenable(dt_proc_t *dpr)
for (dbp = dt_list_next(&dpr->dpr_bps);
dbp != NULL; dbp = dt_list_next(dbp)) {
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#ifdef DOODAD
if (!dbp->dbp_active && Psetbkpt(dpr->dpr_proc,
dbp->dbp_addr, &dbp->dbp_instr) == 0)
dbp->dbp_active = B_TRUE;
#endif
}
dt_dprintf("breakpoints enabled\n");
@ -188,9 +204,12 @@ dt_proc_bpdisable(dt_proc_t *dpr)
for (dbp = dt_list_next(&dpr->dpr_bps);
dbp != NULL; dbp = dt_list_next(dbp)) {
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#ifdef DOODAD
if (dbp->dbp_active && Pdelbkpt(dpr->dpr_proc,
dbp->dbp_addr, dbp->dbp_instr) == 0)
dbp->dbp_active = B_FALSE;
#endif
}
dt_dprintf("breakpoints disabled\n");
@ -263,6 +282,7 @@ dt_proc_bpmain(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *fname)
dt_proc_stop(dpr, DT_PROC_STOP_MAIN);
}
#if defined(sun)
static void
dt_proc_rdevent(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *evname)
{
@ -439,6 +459,7 @@ dt_proc_waitrun(dt_proc_t *dpr)
(void) pthread_mutex_lock(&dpr->dpr_lock);
}
#endif
typedef struct dt_proc_control_data {
dtrace_hdl_t *dpcd_hdl; /* DTrace handle */
@ -465,11 +486,13 @@ dt_proc_control(void *arg)
dt_proc_t *dpr = datap->dpcd_proc;
dt_proc_hash_t *dph = dpr->dpr_hdl->dt_procs;
struct ps_prochandle *P = dpr->dpr_proc;
int pfd = Pctlfd(P);
int pid = dpr->dpr_pid;
#if defined(sun)
int pfd = Pctlfd(P);
const long wstop = PCWSTOP;
#endif
int notify = B_FALSE;
/*
@ -487,6 +510,7 @@ dt_proc_control(void *arg)
*/
(void) pthread_mutex_lock(&dpr->dpr_lock);
#if defined(sun)
(void) Punsetflags(P, PR_ASYNC); /* require synchronous mode */
(void) Psetflags(P, PR_BPTADJ); /* always adjust eip on x86 */
(void) Punsetflags(P, PR_FORK); /* do not inherit on fork */
@ -532,6 +556,20 @@ dt_proc_control(void *arg)
dt_dprintf("pid %d: failed to set running: %s\n",
(int)dpr->dpr_pid, strerror(errno));
}
#else
/*
* If PR_KLC is set, we created the process; otherwise we grabbed it.
* Check for an appropriate stop request and wait for dt_proc_continue.
*/
if (proc_getflags(P) & PR_KLC)
dt_proc_stop(dpr, DT_PROC_STOP_CREATE);
else
dt_proc_stop(dpr, DT_PROC_STOP_GRAB);
if (proc_continue(P) != 0)
dt_dprintf("pid %d: failed to set running: %s\n",
(int)dpr->dpr_pid, strerror(errno));
#endif
(void) pthread_mutex_unlock(&dpr->dpr_lock);
@ -545,20 +583,33 @@ dt_proc_control(void *arg)
* Pwait() (which will return immediately) and do our processing.
*/
while (!dpr->dpr_quit) {
#if defined(sun)
const lwpstatus_t *psp;
if (write(pfd, &wstop, sizeof (wstop)) == -1 && errno == EINTR)
continue; /* check dpr_quit and continue waiting */
#else
/* Wait for the process to report status. */
proc_wait(P);
#endif
(void) pthread_mutex_lock(&dpr->dpr_lock);
#if defined(sun)
pwait_locked:
if (Pstopstatus(P, PCNULL, 0) == -1 && errno == EINTR) {
(void) pthread_mutex_unlock(&dpr->dpr_lock);
continue; /* check dpr_quit and continue waiting */
}
#endif
#if defined(sun)
switch (Pstate(P)) {
#else
switch (proc_state(P)) {
#endif
case PS_STOP:
#ifdef DOODAD
psp = &Pstatus(P)->pr_lwp;
dt_dprintf("pid %d: proc stopped showing %d/%d\n",
@ -601,11 +652,14 @@ dt_proc_control(void *arg)
else if (psp->pr_why == PR_SYSEXIT &&
IS_SYS_EXEC(psp->pr_what))
dt_proc_attach(dpr, B_TRUE);
#endif
break;
case PS_LOST:
#if defined(sun)
if (Preopen(P) == 0)
goto pwait_locked;
#endif
dt_dprintf("pid %d: proc lost: %s\n",
pid, strerror(errno));
@ -621,10 +675,12 @@ dt_proc_control(void *arg)
break;
}
#if defined(sun)
if (Pstate(P) != PS_UNDEAD && Psetrun(P, 0, 0) == -1) {
dt_dprintf("pid %d: failed to set running: %s\n",
(int)dpr->dpr_pid, strerror(errno));
}
#endif
(void) pthread_mutex_unlock(&dpr->dpr_lock);
}
@ -664,7 +720,11 @@ dt_proc_error(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *format, ...)
va_end(ap);
if (dpr->dpr_proc != NULL)
#if defined(sun)
Prelease(dpr->dpr_proc, 0);
#else
proc_detach(dpr->dpr_proc);
#endif
dt_free(dtp, dpr);
(void) dt_set_errno(dtp, EDT_COMPILER);
@ -675,7 +735,11 @@ dt_proc_t *
dt_proc_lookup(dtrace_hdl_t *dtp, struct ps_prochandle *P, int remove)
{
dt_proc_hash_t *dph = dtp->dt_procs;
#if defined(sun)
pid_t pid = Pstatus(P)->pr_pid;
#else
pid_t pid = proc_getpid(P);
#endif
dt_proc_t *dpr, **dpp = &dph->dph_hash[pid & (dph->dph_hashlen - 1)];
for (dpr = *dpp; dpr != NULL; dpr = dpr->dpr_hash) {
@ -709,9 +773,17 @@ dt_proc_destroy(dtrace_hdl_t *dtp, struct ps_prochandle *P)
* an external debugger and we were waiting in dt_proc_waitrun().
* Leave the process in this condition using PRELEASE_HANG.
*/
#if defined(sun)
if (!(Pstatus(dpr->dpr_proc)->pr_flags & (PR_KLC | PR_RLC))) {
#else
if (!(proc_getflags(dpr->dpr_proc) & (PR_KLC | PR_RLC))) {
#endif
dt_dprintf("abandoning pid %d\n", (int)dpr->dpr_pid);
#if defined(sun)
rflag = PRELEASE_HANG;
#else
rflag = 0 /* XXX */;
#endif
} else {
dt_dprintf("releasing pid %d\n", (int)dpr->dpr_pid);
rflag = 0; /* apply kill or run-on-last-close */
@ -734,7 +806,11 @@ dt_proc_destroy(dtrace_hdl_t *dtp, struct ps_prochandle *P)
*/
(void) pthread_mutex_lock(&dpr->dpr_lock);
dpr->dpr_quit = B_TRUE;
#if defined(sun)
(void) _lwp_kill(dpr->dpr_tid, SIGCANCEL);
#else
(void) pthread_kill(dpr->dpr_tid, SIGUSR1);
#endif
/*
* If the process is currently idling in dt_proc_stop(), re-
@ -782,7 +858,11 @@ dt_proc_destroy(dtrace_hdl_t *dtp, struct ps_prochandle *P)
}
dt_list_delete(&dph->dph_lrulist, dpr);
#if defined(sun)
Prelease(dpr->dpr_proc, rflag);
#else
proc_detach(dpr->dpr_proc);
#endif
dt_free(dtp, dpr);
}
@ -802,7 +882,11 @@ dt_proc_create_thread(dtrace_hdl_t *dtp, dt_proc_t *dpr, uint_t stop)
(void) sigfillset(&nset);
(void) sigdelset(&nset, SIGABRT); /* unblocked for assert() */
#if defined(sun)
(void) sigdelset(&nset, SIGCANCEL); /* see dt_proc_destroy() */
#else
(void) sigdelset(&nset, SIGUSR1); /* see dt_proc_destroy() */
#endif
data.dpcd_hdl = dtp;
data.dpcd_proc = dpr;
@ -830,14 +914,21 @@ dt_proc_create_thread(dtrace_hdl_t *dtp, dt_proc_t *dpr, uint_t stop)
* small amount of useful information to help figure it out.
*/
if (dpr->dpr_done) {
#if defined(sun)
const psinfo_t *prp = Ppsinfo(dpr->dpr_proc);
int stat = prp ? prp->pr_wstat : 0;
#endif
int pid = dpr->dpr_pid;
#if defined(sun)
if (Pstate(dpr->dpr_proc) == PS_LOST) {
#else
if (proc_state(dpr->dpr_proc) == PS_LOST) {
#endif
(void) dt_proc_error(dpr->dpr_hdl, dpr,
"failed to control pid %d: process exec'd "
"set-id or unobservable program\n", pid);
#if defined(sun)
} else if (WIFSIGNALED(stat)) {
(void) dt_proc_error(dpr->dpr_hdl, dpr,
"failed to control pid %d: process died "
@ -846,6 +937,7 @@ dt_proc_create_thread(dtrace_hdl_t *dtp, dt_proc_t *dpr, uint_t stop)
(void) dt_proc_error(dpr->dpr_hdl, dpr,
"failed to control pid %d: process exited "
"with status %d\n", pid, WEXITSTATUS(stat));
#endif
}
err = ESRCH; /* cause grab() or create() to fail */
@ -875,6 +967,7 @@ dt_proc_create(dtrace_hdl_t *dtp, const char *file, char *const *argv)
(void) pthread_mutex_init(&dpr->dpr_lock, NULL);
(void) pthread_cond_init(&dpr->dpr_cv, NULL);
#if defined(sun)
if ((dpr->dpr_proc = Pcreate(file, argv, &err, NULL, 0)) == NULL) {
return (dt_proc_error(dtp, dpr,
"failed to execute %s: %s\n", file, Pcreate_error(err)));
@ -885,8 +978,21 @@ dt_proc_create(dtrace_hdl_t *dtp, const char *file, char *const *argv)
(void) Punsetflags(dpr->dpr_proc, PR_RLC);
(void) Psetflags(dpr->dpr_proc, PR_KLC);
#else
(void) proc_clearflags(dpr->dpr_proc, PR_RLC);
(void) proc_setflags(dpr->dpr_proc, PR_KLC);
if ((err = proc_create(file, argv, &dpr->dpr_proc)) != 0)
return (dt_proc_error(dtp, dpr,
"failed to execute %s: %s\n", file, strerror(err)));
dpr->dpr_hdl = dtp;
dpr->dpr_pid = proc_getpid(dpr->dpr_proc);
#endif
#if defined(sun)
if (dt_proc_create_thread(dtp, dpr, dtp->dt_prcmode) != 0)
#else
if (dt_proc_create_thread(dtp, dpr, DT_PROC_STOP_IDLE) != 0)
#endif
return (NULL); /* dt_proc_error() has been called for us */
dpr->dpr_hash = dph->dph_hash[dpr->dpr_pid & (dph->dph_hashlen - 1)];
@ -942,16 +1048,27 @@ dt_proc_grab(dtrace_hdl_t *dtp, pid_t pid, int flags, int nomonitor)
(void) pthread_mutex_init(&dpr->dpr_lock, NULL);
(void) pthread_cond_init(&dpr->dpr_cv, NULL);
#if defined(sun)
if ((dpr->dpr_proc = Pgrab(pid, flags, &err)) == NULL) {
return (dt_proc_error(dtp, dpr,
"failed to grab pid %d: %s\n", (int)pid, Pgrab_error(err)));
}
#else
if ((err = proc_attach(pid, flags, &dpr->dpr_proc)) != 0)
return (dt_proc_error(dtp, dpr,
"failed to grab pid %d: %s\n", (int) pid, strerror(err)));
#endif
dpr->dpr_hdl = dtp;
dpr->dpr_pid = pid;
#if defined(sun)
(void) Punsetflags(dpr->dpr_proc, PR_KLC);
(void) Psetflags(dpr->dpr_proc, PR_RLC);
#else
(void) proc_clearflags(dpr->dpr_proc, PR_KLC);
(void) proc_setflags(dpr->dpr_proc, PR_RLC);
#endif
/*
* If we are attempting to grab the process without a monitor
@ -1072,7 +1189,11 @@ dtrace_proc_create(dtrace_hdl_t *dtp, const char *file, char *const *argv)
struct ps_prochandle *P = dt_proc_create(dtp, file, argv);
if (P != NULL && idp != NULL && idp->di_id == 0)
#if defined(sun)
idp->di_id = Pstatus(P)->pr_pid; /* $target = created pid */
#else
idp->di_id = proc_getpid(P); /* $target = created pid */
#endif
return (P);
}