コード例 #1
0
ファイル: dt_proc.c プロジェクト: Aj0Ay/dtrace-for-linux
/*
 * Check to see if the control thread was requested to stop when the victim
 * process reached a particular event (why) rather than continuing the victim.
 * If 'why' is set in the stop mask, we wait on dpr_cv for dt_proc_continue().
 * If 'why' is not set, this function returns immediately and does nothing.
 */
static void
dt_proc_stop(dt_proc_t *dpr, uint8_t why)
{
	assert(DT_MUTEX_HELD(&dpr->dpr_lock));
	assert(why != DT_PROC_STOP_IDLE);

	if (dpr->dpr_stop & why) {
		dpr->dpr_stop |= DT_PROC_STOP_IDLE;
		dpr->dpr_stop &= ~why;

		(void) pthread_cond_broadcast(&dpr->dpr_cv);

		/*
		 * We disable breakpoints while stopped to preserve the
		 * integrity of the program text for both our own disassembly
		 * and that of the kernel.
		 */
		dt_proc_bpdisable(dpr);

		while (dpr->dpr_stop & DT_PROC_STOP_IDLE)
			(void) pthread_cond_wait(&dpr->dpr_cv, &dpr->dpr_lock);

		dt_proc_bpenable(dpr);
	}
}
コード例 #2
0
ファイル: dt_proc.c プロジェクト: Aj0Ay/dtrace-for-linux
static void
dt_proc_bpmatch(dtrace_hdl_t *dtp, dt_proc_t *dpr)
{
	const lwpstatus_t *psp = &Pstatus(dpr->dpr_proc)->pr_lwp;
	dt_bkpt_t *dbp;

	assert(DT_MUTEX_HELD(&dpr->dpr_lock));

	for (dbp = dt_list_next(&dpr->dpr_bps);
	    dbp != NULL; dbp = dt_list_next(dbp)) {
		if (psp->pr_reg[R_PC] == dbp->dbp_addr)
			break;
	}

	if (dbp == NULL) {
		dt_dprintf("pid %d: spurious breakpoint wakeup for %lx\n",
		    (int)dpr->dpr_pid, (ulong_t)psp->pr_reg[R_PC]);
		return;
	}

	dt_dprintf("pid %d: hit breakpoint at %lx (%lu)\n",
	    (int)dpr->dpr_pid, (ulong_t)dbp->dbp_addr, ++dbp->dbp_hits);

	dbp->dbp_func(dtp, dpr, dbp->dbp_data);
	(void) Pxecbkpt(dpr->dpr_proc, dbp->dbp_instr);
}
コード例 #3
0
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);
	}
}
コード例 #4
0
ファイル: dt_proc.c プロジェクト: Aj0Ay/dtrace-for-linux
/*
 * Wait for a stopped process to be set running again by some other debugger.
 * This is typically not required by /proc-based debuggers, since the usual
 * model is that one debugger controls one victim.  But DTrace, as usual, has
 * its own needs: the stop() action assumes that prun(1) or some other tool
 * will be applied to resume the victim process.  This could be solved by
 * adding a PCWRUN directive to /proc, but that seems like overkill unless
 * other debuggers end up needing this functionality, so we implement a cheap
 * equivalent to PCWRUN using the set of existing kernel mechanisms.
 *
 * Our intent is really not just to wait for the victim to run, but rather to
 * wait for it to run and then stop again for a reason other than the current
 * PR_REQUESTED stop.  Since PCWSTOP/Pstopstatus() can be applied repeatedly
 * to a stopped process and will return the same result without affecting the
 * victim, we can just perform these operations repeatedly until Pstate()
 * changes, the representative LWP ID changes, or the stop timestamp advances.
 * dt_gproc_control() will then rediscover the new state and continue as usual.
 * When the process is still stopped in the same exact state, we sleep for a
 * brief interval before waiting again so as not to spin consuming CPU cycles.
 */
static void
dt_proc_waitrun(dt_proc_t *dpr)
{
	struct ps_prochandle *P = dpr->dpr_proc;
	const lwpstatus_t *psp = &Pstatus(P)->pr_lwp;

	int krflag = psp->pr_flags & (PR_KLC | PR_RLC);
	timestruc_t tstamp = psp->pr_tstamp;
	lwpid_t lwpid = psp->pr_lwpid;

	const long wstop = PCWSTOP;
	int pfd = Pctlfd(P);

	assert(DT_MUTEX_HELD(&dpr->dpr_lock));
	assert(psp->pr_flags & PR_STOPPED);
	assert(Pstate(P) == PS_STOP);

	/*
	 * While we are waiting for the victim to run, clear PR_KLC and PR_RLC
	 * so that if the libdtrace client is killed, the victim stays stopped.
	 * dt_proc_destroy() will also observe this and perform PRELEASE_HANG.
	 */
	(void) Punsetflags(P, krflag);
	Psync(P);

	(void) pthread_mutex_unlock(&dpr->dpr_lock);

	while (!dpr->dpr_quit) {
		if (write(pfd, &wstop, sizeof (wstop)) == -1 && errno == EINTR)
			continue; /* check dpr_quit and continue waiting */

		(void) pthread_mutex_lock(&dpr->dpr_lock);
		(void) Pstopstatus(P, PCNULL, 0);
		psp = &Pstatus(P)->pr_lwp;

		/*
		 * If we've reached a new state, found a new representative, or
		 * the stop timestamp has changed, restore PR_KLC/PR_RLC to its
		 * original setting and then return with dpr_lock held.
		 */
		if (Pstate(P) != PS_STOP || psp->pr_lwpid != lwpid ||
		    bcmp(&psp->pr_tstamp, &tstamp, sizeof (tstamp)) != 0) {
			(void) Psetflags(P, krflag);
			Psync(P);
			return;
		}

		(void) pthread_mutex_unlock(&dpr->dpr_lock);
		(void) poll(NULL, 0, MILLISEC / 2);
	}

	(void) pthread_mutex_lock(&dpr->dpr_lock);
}
コード例 #5
0
ファイル: dt_proc.c プロジェクト: Aj0Ay/dtrace-for-linux
static void
dt_proc_bpdisable(dt_proc_t *dpr)
{
	dt_bkpt_t *dbp;

	assert(DT_MUTEX_HELD(&dpr->dpr_lock));

	for (dbp = dt_list_next(&dpr->dpr_bps);
	    dbp != NULL; dbp = dt_list_next(dbp)) {
		if (dbp->dbp_active && Pdelbkpt(dpr->dpr_proc,
		    dbp->dbp_addr, dbp->dbp_instr) == 0)
			dbp->dbp_active = B_FALSE;
	}

	dt_dprintf("breakpoints disabled\n");
}
コード例 #6
0
ファイル: dt_proc.c プロジェクト: Aj0Ay/dtrace-for-linux
static void
dt_proc_bpdestroy(dt_proc_t *dpr, int delbkpts)
{
	int state = Pstate(dpr->dpr_proc);
	dt_bkpt_t *dbp, *nbp;

	assert(DT_MUTEX_HELD(&dpr->dpr_lock));

	for (dbp = dt_list_next(&dpr->dpr_bps); dbp != NULL; dbp = nbp) {
		if (delbkpts && dbp->dbp_active &&
		    state != PS_LOST && state != PS_UNDEAD) {
			(void) Pdelbkpt(dpr->dpr_proc,
			    dbp->dbp_addr, dbp->dbp_instr);
		}
		nbp = dt_list_next(dbp);
		dt_list_delete(&dpr->dpr_bps, dbp);
		dt_free(dpr->dpr_hdl, dbp);
	}
}
コード例 #7
0
static void
dt_proc_bpdisable(dt_proc_t *dpr)
{
	dt_bkpt_t *dbp;

	assert(DT_MUTEX_HELD(&dpr->dpr_lock));

	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");
}
コード例 #8
0
static int
dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
    dt_pcb_t *pcb, dt_proc_t *dpr)
{
	struct ps_prochandle *P = dpr->dpr_proc;
	int ret = 0;

	assert(DT_MUTEX_HELD(&dpr->dpr_lock));
#if defined(sun)
	(void) Pupdate_maps(P);
	if (Pobject_iter(P, dt_pid_usdt_mapping, P) != 0) {
		ret = -1;
		(void) dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_USDT,
		    "failed to instantiate probes for pid %d: %s",
#if defined(sun)
		    (int)Pstatus(P)->pr_pid, strerror(errno));
#else
		    (int)proc_getpid(P), strerror(errno));
#endif
	}
コード例 #9
0
ファイル: dt_proc.c プロジェクト: Aj0Ay/dtrace-for-linux
static dt_bkpt_t *
dt_proc_bpcreate(dt_proc_t *dpr, uintptr_t addr, dt_bkpt_f *func, void *data)
{
	struct ps_prochandle *P = dpr->dpr_proc;
	dt_bkpt_t *dbp;

	assert(DT_MUTEX_HELD(&dpr->dpr_lock));

	if ((dbp = dt_zalloc(dpr->dpr_hdl, sizeof (dt_bkpt_t))) != NULL) {
		dbp->dbp_func = func;
		dbp->dbp_data = data;
		dbp->dbp_addr = addr;

		if (Psetbkpt(P, dbp->dbp_addr, &dbp->dbp_instr) == 0)
			dbp->dbp_active = B_TRUE;

		dt_list_append(&dpr->dpr_bps, dbp);
	}

	return (dbp);
}
コード例 #10
0
ファイル: dt_proc.c プロジェクト: Aj0Ay/dtrace-for-linux
/*
 * Common code for enabling events associated with the run-time linker after
 * attaching to a process or after a victim process completes an exec(2).
 */
static void
dt_proc_attach(dt_proc_t *dpr, int exec)
{
	const pstatus_t *psp = Pstatus(dpr->dpr_proc);
	rd_err_e err;
	GElf_Sym sym;

	assert(DT_MUTEX_HELD(&dpr->dpr_lock));

	if (exec) {
		if (psp->pr_lwp.pr_errno != 0)
			return; /* exec failed: nothing needs to be done */

		dt_proc_bpdestroy(dpr, B_FALSE);
		Preset_maps(dpr->dpr_proc);
	}

	if ((dpr->dpr_rtld = Prd_agent(dpr->dpr_proc)) != NULL &&
	    (err = rd_event_enable(dpr->dpr_rtld, B_TRUE)) == RD_OK) {
		dt_proc_rdwatch(dpr, RD_PREINIT, "RD_PREINIT");
		dt_proc_rdwatch(dpr, RD_POSTINIT, "RD_POSTINIT");
		dt_proc_rdwatch(dpr, RD_DLACTIVITY, "RD_DLACTIVITY");
	} else {
		dt_dprintf("pid %d: failed to enable rtld events: %s\n",
		    (int)dpr->dpr_pid, dpr->dpr_rtld ? rd_errstr(err) :
		    "rtld_db agent initialization failed");
	}

	Pupdate_maps(dpr->dpr_proc);

	if (Pxlookup_by_name(dpr->dpr_proc, LM_ID_BASE,
	    "a.out", "main", &sym, NULL) == 0) {
		(void) dt_proc_bpcreate(dpr, (uintptr_t)sym.st_value,
		    (dt_bkpt_f *)dt_proc_bpmain, "a.out`main");
	} else {
		dt_dprintf("pid %d: failed to find a.out`main: %s\n",
		    (int)dpr->dpr_pid, strerror(errno));
	}
}
コード例 #11
0
ファイル: dt_proc.c プロジェクト: ajinkya93/netbsd-src
static void
dt_proc_bpmatch(dtrace_hdl_t *dtp, dt_proc_t *dpr)
{
#ifdef illumos
	const lwpstatus_t *psp = &Pstatus(dpr->dpr_proc)->pr_lwp;
#else
	unsigned long pc;
#endif
	dt_bkpt_t *dbp;

	assert(DT_MUTEX_HELD(&dpr->dpr_lock));

#ifndef illumos
	proc_regget(dpr->dpr_proc, REG_PC, &pc);
	proc_bkptregadj(&pc);
#endif

	for (dbp = dt_list_next(&dpr->dpr_bps);
	    dbp != NULL; dbp = dt_list_next(dbp)) {
#ifdef illumos
		if (psp->pr_reg[R_PC] == dbp->dbp_addr)
			break;
#else
		if (pc == dbp->dbp_addr)
			break;
#endif
	}

	if (dbp == NULL) {
		dt_dprintf("pid %d: spurious breakpoint wakeup for %lx\n",
#ifdef illumos
		    (int)dpr->dpr_pid, (ulong_t)psp->pr_reg[R_PC]);
#else
		    (int)dpr->dpr_pid, pc);
#endif
		return;
	}