1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * DTrace Process Control
31*0Sstevel@tonic-gate  *
32*0Sstevel@tonic-gate  * This file provides a set of routines that permit libdtrace and its clients
33*0Sstevel@tonic-gate  * to create and grab process handles using libproc, and to share these handles
34*0Sstevel@tonic-gate  * between library mechanisms that need libproc access, such as ustack(), and
35*0Sstevel@tonic-gate  * client mechanisms that need libproc access, such as dtrace(1M) -c and -p.
36*0Sstevel@tonic-gate  * The library provides several mechanisms in the libproc control layer:
37*0Sstevel@tonic-gate  *
38*0Sstevel@tonic-gate  * Reference Counting: The library code and client code can independently grab
39*0Sstevel@tonic-gate  * the same process handles without interfering with one another.  Only when
40*0Sstevel@tonic-gate  * the reference count drops to zero and the handle is not being cached (see
41*0Sstevel@tonic-gate  * below for more information on caching) will Prelease() be called on it.
42*0Sstevel@tonic-gate  *
43*0Sstevel@tonic-gate  * Handle Caching: If a handle is grabbed PGRAB_RDONLY (e.g. by ustack()) and
44*0Sstevel@tonic-gate  * the reference count drops to zero, the handle is not immediately released.
45*0Sstevel@tonic-gate  * Instead, libproc handles are maintained on dph_lrulist in order from most-
46*0Sstevel@tonic-gate  * recently accessed to least-recently accessed.  Idle handles are maintained
47*0Sstevel@tonic-gate  * until a pre-defined LRU cache limit is exceeded, permitting repeated calls
48*0Sstevel@tonic-gate  * to ustack() to avoid the overhead of releasing and re-grabbing processes.
49*0Sstevel@tonic-gate  *
50*0Sstevel@tonic-gate  * Process Control: For processes that are grabbed for control (~PGRAB_RDONLY)
51*0Sstevel@tonic-gate  * or created by dt_proc_create(), a control thread is created to provide
52*0Sstevel@tonic-gate  * callbacks on process exit and symbol table caching on dlopen()s.
53*0Sstevel@tonic-gate  *
54*0Sstevel@tonic-gate  * MT-Safety: Libproc is not MT-Safe, so dt_proc_lock() and dt_proc_unlock()
55*0Sstevel@tonic-gate  * are provided to synchronize access to the libproc handle between libdtrace
56*0Sstevel@tonic-gate  * code and client code and the control thread's use of the ps_prochandle.
57*0Sstevel@tonic-gate  *
58*0Sstevel@tonic-gate  * NOTE: MT-Safety is NOT provided for libdtrace itself, or for use of the
59*0Sstevel@tonic-gate  * dtrace_proc_grab/dtrace_proc_create mechanisms.  Like all exported libdtrace
60*0Sstevel@tonic-gate  * calls, these are assumed to be MT-Unsafe.  MT-Safety is ONLY provided for
61*0Sstevel@tonic-gate  * synchronization between libdtrace control threads and the client thread.
62*0Sstevel@tonic-gate  *
63*0Sstevel@tonic-gate  * The ps_prochandles themselves are maintained along with a dt_proc_t struct
64*0Sstevel@tonic-gate  * in a hash table indexed by PID.  This provides basic locking and reference
65*0Sstevel@tonic-gate  * counting.  The dt_proc_t is also maintained in LRU order on dph_lrulist.
66*0Sstevel@tonic-gate  * The dph_lrucnt and dph_lrulim count the number of cacheable processes and
67*0Sstevel@tonic-gate  * the current limit on the number of actively cached entries.
68*0Sstevel@tonic-gate  *
69*0Sstevel@tonic-gate  * The control thread for a process establishes breakpoints at the rtld_db
70*0Sstevel@tonic-gate  * locations of interest, updates mappings and symbol tables at these points,
71*0Sstevel@tonic-gate  * and handles exec and fork (by always following the parent).  The control
72*0Sstevel@tonic-gate  * thread automatically exits when the process dies or control is lost.
73*0Sstevel@tonic-gate  *
74*0Sstevel@tonic-gate  * A simple notification mechanism is provided for libdtrace clients using
75*0Sstevel@tonic-gate  * dtrace_handle_proc() for notification of PS_UNDEAD or PS_LOST events.  If
76*0Sstevel@tonic-gate  * such an event occurs, the dt_proc_t itself is enqueued on a notification
77*0Sstevel@tonic-gate  * list and the control thread broadcasts to dph_cv.  dtrace_sleep() will wake
78*0Sstevel@tonic-gate  * up using this condition and will then call the client handler as necessary.
79*0Sstevel@tonic-gate  */
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate #include <sys/wait.h>
82*0Sstevel@tonic-gate #include <sys/lwp.h>
83*0Sstevel@tonic-gate #include <strings.h>
84*0Sstevel@tonic-gate #include <signal.h>
85*0Sstevel@tonic-gate #include <assert.h>
86*0Sstevel@tonic-gate #include <errno.h>
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate #include <dt_proc.h>
89*0Sstevel@tonic-gate #include <dt_pid.h>
90*0Sstevel@tonic-gate #include <dt_impl.h>
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate #define	IS_SYS_EXEC(w)	(w == SYS_exec || w == SYS_execve)
93*0Sstevel@tonic-gate #define	IS_SYS_FORK(w)	(w == SYS_vfork || w == SYS_fork1 || w == SYS_forkall)
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate static dt_bkpt_t *
96*0Sstevel@tonic-gate dt_proc_bpcreate(dt_proc_t *dpr, uintptr_t addr, dt_bkpt_f *func, void *data)
97*0Sstevel@tonic-gate {
98*0Sstevel@tonic-gate 	struct ps_prochandle *P = dpr->dpr_proc;
99*0Sstevel@tonic-gate 	dt_bkpt_t *dbp;
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 	assert(DT_MUTEX_HELD(&dpr->dpr_lock));
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate 	if ((dbp = dt_zalloc(dpr->dpr_hdl, sizeof (dt_bkpt_t))) != NULL) {
104*0Sstevel@tonic-gate 		dbp->dbp_func = func;
105*0Sstevel@tonic-gate 		dbp->dbp_data = data;
106*0Sstevel@tonic-gate 		dbp->dbp_addr = addr;
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate 		if (Psetbkpt(P, dbp->dbp_addr, &dbp->dbp_instr) == 0)
109*0Sstevel@tonic-gate 			dbp->dbp_active = B_TRUE;
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 		dt_list_append(&dpr->dpr_bps, dbp);
112*0Sstevel@tonic-gate 	}
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate 	return (dbp);
115*0Sstevel@tonic-gate }
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate static void
118*0Sstevel@tonic-gate dt_proc_bpdestroy(dt_proc_t *dpr, int delbkpts)
119*0Sstevel@tonic-gate {
120*0Sstevel@tonic-gate 	int state = Pstate(dpr->dpr_proc);
121*0Sstevel@tonic-gate 	dt_bkpt_t *dbp, *nbp;
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate 	assert(DT_MUTEX_HELD(&dpr->dpr_lock));
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate 	for (dbp = dt_list_next(&dpr->dpr_bps); dbp != NULL; dbp = nbp) {
126*0Sstevel@tonic-gate 		if (delbkpts && dbp->dbp_active &&
127*0Sstevel@tonic-gate 		    state != PS_LOST && state != PS_UNDEAD) {
128*0Sstevel@tonic-gate 			(void) Pdelbkpt(dpr->dpr_proc,
129*0Sstevel@tonic-gate 			    dbp->dbp_addr, dbp->dbp_instr);
130*0Sstevel@tonic-gate 		}
131*0Sstevel@tonic-gate 		nbp = dt_list_next(dbp);
132*0Sstevel@tonic-gate 		dt_list_delete(&dpr->dpr_bps, dbp);
133*0Sstevel@tonic-gate 		dt_free(dpr->dpr_hdl, dbp);
134*0Sstevel@tonic-gate 	}
135*0Sstevel@tonic-gate }
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate static void
138*0Sstevel@tonic-gate dt_proc_bpmatch(dtrace_hdl_t *dtp, dt_proc_t *dpr)
139*0Sstevel@tonic-gate {
140*0Sstevel@tonic-gate 	const lwpstatus_t *psp = &Pstatus(dpr->dpr_proc)->pr_lwp;
141*0Sstevel@tonic-gate 	dt_bkpt_t *dbp;
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate 	assert(DT_MUTEX_HELD(&dpr->dpr_lock));
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate 	for (dbp = dt_list_next(&dpr->dpr_bps);
146*0Sstevel@tonic-gate 	    dbp != NULL; dbp = dt_list_next(dbp)) {
147*0Sstevel@tonic-gate 		if (psp->pr_reg[R_PC] == dbp->dbp_addr)
148*0Sstevel@tonic-gate 			break;
149*0Sstevel@tonic-gate 	}
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate 	if (dbp == NULL) {
152*0Sstevel@tonic-gate 		dt_dprintf("pid %d: spurious breakpoint wakeup for %lx\n",
153*0Sstevel@tonic-gate 		    (int)dpr->dpr_pid, (ulong_t)psp->pr_reg[R_PC]);
154*0Sstevel@tonic-gate 		return;
155*0Sstevel@tonic-gate 	}
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate 	dt_dprintf("pid %d: hit breakpoint at %lx (%lu)\n",
158*0Sstevel@tonic-gate 	    (int)dpr->dpr_pid, (ulong_t)dbp->dbp_addr, ++dbp->dbp_hits);
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate 	dbp->dbp_func(dtp, dpr, dbp->dbp_data);
161*0Sstevel@tonic-gate 	(void) Pxecbkpt(dpr->dpr_proc, dbp->dbp_instr);
162*0Sstevel@tonic-gate }
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate static void
165*0Sstevel@tonic-gate dt_proc_bpenable(dt_proc_t *dpr)
166*0Sstevel@tonic-gate {
167*0Sstevel@tonic-gate 	dt_bkpt_t *dbp;
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate 	assert(DT_MUTEX_HELD(&dpr->dpr_lock));
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 	for (dbp = dt_list_next(&dpr->dpr_bps);
172*0Sstevel@tonic-gate 	    dbp != NULL; dbp = dt_list_next(dbp)) {
173*0Sstevel@tonic-gate 		if (!dbp->dbp_active && Psetbkpt(dpr->dpr_proc,
174*0Sstevel@tonic-gate 		    dbp->dbp_addr, &dbp->dbp_instr) == 0)
175*0Sstevel@tonic-gate 			dbp->dbp_active = B_TRUE;
176*0Sstevel@tonic-gate 	}
177*0Sstevel@tonic-gate }
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate static void
180*0Sstevel@tonic-gate dt_proc_bpdisable(dt_proc_t *dpr)
181*0Sstevel@tonic-gate {
182*0Sstevel@tonic-gate 	dt_bkpt_t *dbp;
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 	assert(DT_MUTEX_HELD(&dpr->dpr_lock));
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate 	for (dbp = dt_list_next(&dpr->dpr_bps);
187*0Sstevel@tonic-gate 	    dbp != NULL; dbp = dt_list_next(dbp)) {
188*0Sstevel@tonic-gate 		if (dbp->dbp_active && Pdelbkpt(dpr->dpr_proc,
189*0Sstevel@tonic-gate 		    dbp->dbp_addr, dbp->dbp_instr) == 0)
190*0Sstevel@tonic-gate 			dbp->dbp_active = B_FALSE;
191*0Sstevel@tonic-gate 	}
192*0Sstevel@tonic-gate }
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate /*
195*0Sstevel@tonic-gate  * Check to see if the control thread was requested to stop when the victim
196*0Sstevel@tonic-gate  * process reached a particular event (why) rather than continuing the victim.
197*0Sstevel@tonic-gate  * If 'why' is set in the stop mask, we wait on dpr_cv for dt_proc_continue().
198*0Sstevel@tonic-gate  * If 'why' is not set, this function returns immediately and does nothing.
199*0Sstevel@tonic-gate  */
200*0Sstevel@tonic-gate static void
201*0Sstevel@tonic-gate dt_proc_stop(dt_proc_t *dpr, uint8_t why)
202*0Sstevel@tonic-gate {
203*0Sstevel@tonic-gate 	assert(DT_MUTEX_HELD(&dpr->dpr_lock));
204*0Sstevel@tonic-gate 	assert(why != DT_PROC_STOP_IDLE);
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 	if (dpr->dpr_stop & why) {
207*0Sstevel@tonic-gate 		dpr->dpr_stop |= DT_PROC_STOP_IDLE;
208*0Sstevel@tonic-gate 		dpr->dpr_stop &= ~why;
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate 		(void) pthread_cond_broadcast(&dpr->dpr_cv);
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 		while (dpr->dpr_stop & DT_PROC_STOP_IDLE)
213*0Sstevel@tonic-gate 			(void) pthread_cond_wait(&dpr->dpr_cv, &dpr->dpr_lock);
214*0Sstevel@tonic-gate 	}
215*0Sstevel@tonic-gate }
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate /*ARGSUSED*/
218*0Sstevel@tonic-gate static void
219*0Sstevel@tonic-gate dt_proc_bpmain(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *fname)
220*0Sstevel@tonic-gate {
221*0Sstevel@tonic-gate 	dt_dprintf("pid %d: breakpoint at %s()\n", (int)dpr->dpr_pid, fname);
222*0Sstevel@tonic-gate 	dt_proc_stop(dpr, DT_PROC_STOP_MAIN);
223*0Sstevel@tonic-gate }
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate static void
226*0Sstevel@tonic-gate dt_proc_rdevent(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *evname)
227*0Sstevel@tonic-gate {
228*0Sstevel@tonic-gate 	rd_event_msg_t rdm;
229*0Sstevel@tonic-gate 	rd_err_e err;
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 	if ((err = rd_event_getmsg(dpr->dpr_rtld, &rdm)) != RD_OK) {
232*0Sstevel@tonic-gate 		dt_dprintf("pid %d: failed to get %s event message: %s\n",
233*0Sstevel@tonic-gate 		    (int)dpr->dpr_pid, evname, rd_errstr(err));
234*0Sstevel@tonic-gate 		return;
235*0Sstevel@tonic-gate 	}
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate 	dt_dprintf("pid %d: rtld event %s type=%d state %d\n",
238*0Sstevel@tonic-gate 	    (int)dpr->dpr_pid, evname, rdm.type, rdm.u.state);
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 	switch (rdm.type) {
241*0Sstevel@tonic-gate 	case RD_DLACTIVITY:
242*0Sstevel@tonic-gate 		if (rdm.u.state == RD_CONSISTENT) {
243*0Sstevel@tonic-gate 			Pupdate_syms(dpr->dpr_proc);
244*0Sstevel@tonic-gate 			dt_proc_bpdisable(dpr);
245*0Sstevel@tonic-gate 			dt_pid_create_probes_module(dtp, dpr);
246*0Sstevel@tonic-gate 			dt_proc_bpenable(dpr);
247*0Sstevel@tonic-gate 		}
248*0Sstevel@tonic-gate 		break;
249*0Sstevel@tonic-gate 	case RD_PREINIT:
250*0Sstevel@tonic-gate 		Pupdate_syms(dpr->dpr_proc);
251*0Sstevel@tonic-gate 		dt_proc_stop(dpr, DT_PROC_STOP_PREINIT);
252*0Sstevel@tonic-gate 		break;
253*0Sstevel@tonic-gate 	case RD_POSTINIT:
254*0Sstevel@tonic-gate 		Pupdate_syms(dpr->dpr_proc);
255*0Sstevel@tonic-gate 		dt_proc_stop(dpr, DT_PROC_STOP_POSTINIT);
256*0Sstevel@tonic-gate 		break;
257*0Sstevel@tonic-gate 	}
258*0Sstevel@tonic-gate }
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate static void
261*0Sstevel@tonic-gate dt_proc_rdwatch(dt_proc_t *dpr, rd_event_e event, const char *evname)
262*0Sstevel@tonic-gate {
263*0Sstevel@tonic-gate 	rd_notify_t rdn;
264*0Sstevel@tonic-gate 	rd_err_e err;
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	if ((err = rd_event_addr(dpr->dpr_rtld, event, &rdn)) != RD_OK) {
267*0Sstevel@tonic-gate 		dt_dprintf("pid %d: failed to get event address for %s: %s\n",
268*0Sstevel@tonic-gate 		    (int)dpr->dpr_pid, evname, rd_errstr(err));
269*0Sstevel@tonic-gate 		return;
270*0Sstevel@tonic-gate 	}
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 	if (rdn.type != RD_NOTIFY_BPT) {
273*0Sstevel@tonic-gate 		dt_dprintf("pid %d: event %s has unexpected type %d\n",
274*0Sstevel@tonic-gate 		    (int)dpr->dpr_pid, evname, rdn.type);
275*0Sstevel@tonic-gate 		return;
276*0Sstevel@tonic-gate 	}
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	(void) dt_proc_bpcreate(dpr, rdn.u.bptaddr,
279*0Sstevel@tonic-gate 	    (dt_bkpt_f *)dt_proc_rdevent, (void *)evname);
280*0Sstevel@tonic-gate }
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate /*
283*0Sstevel@tonic-gate  * Common code for enabling events associated with the run-time linker after
284*0Sstevel@tonic-gate  * attaching to a process or after a victim process completes an exec(2).
285*0Sstevel@tonic-gate  */
286*0Sstevel@tonic-gate static void
287*0Sstevel@tonic-gate dt_proc_attach(dt_proc_t *dpr, int exec)
288*0Sstevel@tonic-gate {
289*0Sstevel@tonic-gate 	const pstatus_t *psp = Pstatus(dpr->dpr_proc);
290*0Sstevel@tonic-gate 	rd_err_e err;
291*0Sstevel@tonic-gate 	GElf_Sym sym;
292*0Sstevel@tonic-gate 
293*0Sstevel@tonic-gate 	assert(DT_MUTEX_HELD(&dpr->dpr_lock));
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate 	if (exec) {
296*0Sstevel@tonic-gate 		if (psp->pr_lwp.pr_errno != 0)
297*0Sstevel@tonic-gate 			return; /* exec failed: nothing needs to be done */
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 		dt_proc_bpdestroy(dpr, B_FALSE);
300*0Sstevel@tonic-gate 		Preset_maps(dpr->dpr_proc);
301*0Sstevel@tonic-gate 	}
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate 	if ((dpr->dpr_rtld = Prd_agent(dpr->dpr_proc)) != NULL &&
304*0Sstevel@tonic-gate 	    (err = rd_event_enable(dpr->dpr_rtld, B_TRUE)) == RD_OK) {
305*0Sstevel@tonic-gate 		dt_proc_rdwatch(dpr, RD_PREINIT, "RD_PREINIT");
306*0Sstevel@tonic-gate 		dt_proc_rdwatch(dpr, RD_POSTINIT, "RD_POSTINIT");
307*0Sstevel@tonic-gate 		dt_proc_rdwatch(dpr, RD_DLACTIVITY, "RD_DLACTIVITY");
308*0Sstevel@tonic-gate 	} else {
309*0Sstevel@tonic-gate 		dt_dprintf("pid %d: failed to enable rtld events: %s\n",
310*0Sstevel@tonic-gate 		    (int)dpr->dpr_pid, dpr->dpr_rtld ? rd_errstr(err) :
311*0Sstevel@tonic-gate 		    "rtld_db agent initialization failed");
312*0Sstevel@tonic-gate 	}
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate 	Pupdate_maps(dpr->dpr_proc);
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	if (Pxlookup_by_name(dpr->dpr_proc, LM_ID_BASE,
317*0Sstevel@tonic-gate 	    "a.out", "main", &sym, NULL) == 0) {
318*0Sstevel@tonic-gate 		(void) dt_proc_bpcreate(dpr, (uintptr_t)sym.st_value,
319*0Sstevel@tonic-gate 		    (dt_bkpt_f *)dt_proc_bpmain, "a.out`main");
320*0Sstevel@tonic-gate 	} else {
321*0Sstevel@tonic-gate 		dt_dprintf("pid %d: failed to find a.out`main: %s\n",
322*0Sstevel@tonic-gate 		    (int)dpr->dpr_pid, strerror(errno));
323*0Sstevel@tonic-gate 	}
324*0Sstevel@tonic-gate }
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate /*
327*0Sstevel@tonic-gate  * Wait for a stopped process to be set running again by some other debugger.
328*0Sstevel@tonic-gate  * This is typically not required by /proc-based debuggers, since the usual
329*0Sstevel@tonic-gate  * model is that one debugger controls one victim.  But DTrace, as usual, has
330*0Sstevel@tonic-gate  * its own needs: the stop() action assumes that prun(1) or some other tool
331*0Sstevel@tonic-gate  * will be applied to resume the victim process.  This could be solved by
332*0Sstevel@tonic-gate  * adding a PCWRUN directive to /proc, but that seems like overkill unless
333*0Sstevel@tonic-gate  * other debuggers end up needing this functionality, so we implement a cheap
334*0Sstevel@tonic-gate  * equivalent to PCWRUN using the set of existing kernel mechanisms.
335*0Sstevel@tonic-gate  *
336*0Sstevel@tonic-gate  * Our intent is really not just to wait for the victim to run, but rather to
337*0Sstevel@tonic-gate  * wait for it to run and then stop again for a reason other than the current
338*0Sstevel@tonic-gate  * PR_REQUESTED stop.  Since PCWSTOP/Pstopstatus() can be applied repeatedly
339*0Sstevel@tonic-gate  * to a stopped process and will return the same result without affecting the
340*0Sstevel@tonic-gate  * victim, we can just perform these operations repeatedly until Pstate()
341*0Sstevel@tonic-gate  * changes, the representative LWP ID changes, or the stop timestamp advances.
342*0Sstevel@tonic-gate  * dt_proc_control() will then rediscover the new state and continue as usual.
343*0Sstevel@tonic-gate  * When the process is still stopped in the same exact state, we sleep for a
344*0Sstevel@tonic-gate  * brief interval before waiting again so as not to spin consuming CPU cycles.
345*0Sstevel@tonic-gate  */
346*0Sstevel@tonic-gate static void
347*0Sstevel@tonic-gate dt_proc_waitrun(dt_proc_t *dpr)
348*0Sstevel@tonic-gate {
349*0Sstevel@tonic-gate 	struct ps_prochandle *P = dpr->dpr_proc;
350*0Sstevel@tonic-gate 	const lwpstatus_t *psp = &Pstatus(P)->pr_lwp;
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate 	int krflag = psp->pr_flags & (PR_KLC | PR_RLC);
353*0Sstevel@tonic-gate 	timestruc_t tstamp = psp->pr_tstamp;
354*0Sstevel@tonic-gate 	lwpid_t lwpid = psp->pr_lwpid;
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate 	const long wstop = PCWSTOP;
357*0Sstevel@tonic-gate 	int pfd = Pctlfd(P);
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 	assert(DT_MUTEX_HELD(&dpr->dpr_lock));
360*0Sstevel@tonic-gate 	assert(psp->pr_flags & PR_STOPPED);
361*0Sstevel@tonic-gate 	assert(Pstate(P) == PS_STOP);
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 	/*
364*0Sstevel@tonic-gate 	 * While we are waiting for the victim to run, clear PR_KLC and PR_RLC
365*0Sstevel@tonic-gate 	 * so that if the libdtrace client is killed, the victim stays stopped.
366*0Sstevel@tonic-gate 	 * dt_proc_destroy() will also observe this and perform PRELEASE_HANG.
367*0Sstevel@tonic-gate 	 */
368*0Sstevel@tonic-gate 	(void) Punsetflags(P, krflag);
369*0Sstevel@tonic-gate 	Psync(P);
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&dpr->dpr_lock);
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 	while (!dpr->dpr_quit) {
374*0Sstevel@tonic-gate 		if (write(pfd, &wstop, sizeof (wstop)) == -1 && errno == EINTR)
375*0Sstevel@tonic-gate 			continue; /* check dpr_quit and continue waiting */
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 		(void) pthread_mutex_lock(&dpr->dpr_lock);
378*0Sstevel@tonic-gate 		(void) Pstopstatus(P, PCNULL, 0);
379*0Sstevel@tonic-gate 		psp = &Pstatus(P)->pr_lwp;
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate 		/*
382*0Sstevel@tonic-gate 		 * If we've reached a new state, found a new representative, or
383*0Sstevel@tonic-gate 		 * the stop timestamp has changed, restore PR_KLC/PR_RLC to its
384*0Sstevel@tonic-gate 		 * original setting and then return with dpr_lock held.
385*0Sstevel@tonic-gate 		 */
386*0Sstevel@tonic-gate 		if (Pstate(P) != PS_STOP || psp->pr_lwpid != lwpid ||
387*0Sstevel@tonic-gate 		    bcmp(&psp->pr_tstamp, &tstamp, sizeof (tstamp)) != 0) {
388*0Sstevel@tonic-gate 			(void) Psetflags(P, krflag);
389*0Sstevel@tonic-gate 			Psync(P);
390*0Sstevel@tonic-gate 			return;
391*0Sstevel@tonic-gate 		}
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&dpr->dpr_lock);
394*0Sstevel@tonic-gate 		(void) poll(NULL, 0, MILLISEC / 2);
395*0Sstevel@tonic-gate 	}
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate 	(void) pthread_mutex_lock(&dpr->dpr_lock);
398*0Sstevel@tonic-gate }
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate typedef struct dt_proc_control_data {
401*0Sstevel@tonic-gate 	dtrace_hdl_t *dpcd_hdl;			/* DTrace handle */
402*0Sstevel@tonic-gate 	dt_proc_t *dpcd_proc;			/* proccess to control */
403*0Sstevel@tonic-gate } dt_proc_control_data_t;
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate /*
406*0Sstevel@tonic-gate  * Main loop for all victim process control threads.  We initialize all the
407*0Sstevel@tonic-gate  * appropriate /proc control mechanisms, and then enter a loop waiting for
408*0Sstevel@tonic-gate  * the process to stop on an event or die.  We process any events by calling
409*0Sstevel@tonic-gate  * appropriate subroutines, and exit when the victim dies or we lose control.
410*0Sstevel@tonic-gate  *
411*0Sstevel@tonic-gate  * The control thread synchronizes the use of dpr_proc with other libdtrace
412*0Sstevel@tonic-gate  * threads using dpr_lock.  We hold the lock for all of our operations except
413*0Sstevel@tonic-gate  * waiting while the process is running: this is accomplished by writing a
414*0Sstevel@tonic-gate  * PCWSTOP directive directly to the underlying /proc/<pid>/ctl file.  If the
415*0Sstevel@tonic-gate  * libdtrace client wishes to exit or abort our wait, SIGCANCEL can be used.
416*0Sstevel@tonic-gate  */
417*0Sstevel@tonic-gate static void *
418*0Sstevel@tonic-gate dt_proc_control(void *arg)
419*0Sstevel@tonic-gate {
420*0Sstevel@tonic-gate 	dt_proc_control_data_t *datap = arg;
421*0Sstevel@tonic-gate 	dtrace_hdl_t *dtp = datap->dpcd_hdl;
422*0Sstevel@tonic-gate 	dt_proc_t *dpr = datap->dpcd_proc;
423*0Sstevel@tonic-gate 	dt_proc_hash_t *dph = dpr->dpr_hdl->dt_procs;
424*0Sstevel@tonic-gate 	struct ps_prochandle *P = dpr->dpr_proc;
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 	int pfd = Pctlfd(P);
427*0Sstevel@tonic-gate 	int pid = dpr->dpr_pid;
428*0Sstevel@tonic-gate 
429*0Sstevel@tonic-gate 	const long wstop = PCWSTOP;
430*0Sstevel@tonic-gate 	int notify = B_FALSE;
431*0Sstevel@tonic-gate 
432*0Sstevel@tonic-gate 	/*
433*0Sstevel@tonic-gate 	 * We disable the POSIX thread cancellation mechanism so that the
434*0Sstevel@tonic-gate 	 * client program using libdtrace can't accidentally cancel our thread.
435*0Sstevel@tonic-gate 	 * dt_proc_destroy() uses SIGCANCEL explicitly to simply poke us out
436*0Sstevel@tonic-gate 	 * of PCWSTOP with EINTR, at which point we will see dpr_quit and exit.
437*0Sstevel@tonic-gate 	 */
438*0Sstevel@tonic-gate 	(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate 	/*
441*0Sstevel@tonic-gate 	 * Set up the corresponding process for tracing by libdtrace.  We want
442*0Sstevel@tonic-gate 	 * to be able to catch breakpoints and efficiently single-step over
443*0Sstevel@tonic-gate 	 * them, and we need to enable librtld_db to watch libdl activity.
444*0Sstevel@tonic-gate 	 */
445*0Sstevel@tonic-gate 	(void) pthread_mutex_lock(&dpr->dpr_lock);
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 	(void) Punsetflags(P, PR_ASYNC);	/* require synchronous mode */
448*0Sstevel@tonic-gate 	(void) Psetflags(P, PR_BPTADJ);		/* always adjust eip on x86 */
449*0Sstevel@tonic-gate 	(void) Punsetflags(P, PR_FORK);		/* do not inherit on fork */
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 	(void) Pfault(P, FLTBPT, B_TRUE);	/* always trace breakpoints */
452*0Sstevel@tonic-gate 	(void) Pfault(P, FLTTRACE, B_TRUE);	/* always trace single-step */
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 	/*
455*0Sstevel@tonic-gate 	 * We must trace exit from exec() system calls so that if the exec is
456*0Sstevel@tonic-gate 	 * successful, we can reset our breakpoints and re-initialize libproc.
457*0Sstevel@tonic-gate 	 */
458*0Sstevel@tonic-gate 	(void) Psysexit(P, SYS_exec, B_TRUE);
459*0Sstevel@tonic-gate 	(void) Psysexit(P, SYS_execve, B_TRUE);
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate 	/*
462*0Sstevel@tonic-gate 	 * We must trace entry and exit for fork() system calls in order to
463*0Sstevel@tonic-gate 	 * disable our breakpoints temporarily during the fork.  We do not set
464*0Sstevel@tonic-gate 	 * the PR_FORK flag, so if fork succeeds the child begins executing and
465*0Sstevel@tonic-gate 	 * does not inherit any other tracing behaviors or a control thread.
466*0Sstevel@tonic-gate 	 */
467*0Sstevel@tonic-gate 	(void) Psysentry(P, SYS_vfork, B_TRUE);
468*0Sstevel@tonic-gate 	(void) Psysexit(P, SYS_vfork, B_TRUE);
469*0Sstevel@tonic-gate 	(void) Psysentry(P, SYS_fork1, B_TRUE);
470*0Sstevel@tonic-gate 	(void) Psysexit(P, SYS_fork1, B_TRUE);
471*0Sstevel@tonic-gate 	(void) Psysentry(P, SYS_forkall, B_TRUE);
472*0Sstevel@tonic-gate 	(void) Psysexit(P, SYS_forkall, B_TRUE);
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate 	Psync(P);				/* enable all /proc changes */
475*0Sstevel@tonic-gate 	dt_proc_attach(dpr, B_FALSE);		/* enable rtld breakpoints */
476*0Sstevel@tonic-gate 
477*0Sstevel@tonic-gate 	/*
478*0Sstevel@tonic-gate 	 * If PR_KLC is set, we created the process; otherwise we grabbed it.
479*0Sstevel@tonic-gate 	 * Check for an appropriate stop request and wait for dt_proc_continue.
480*0Sstevel@tonic-gate 	 */
481*0Sstevel@tonic-gate 	if (Pstatus(P)->pr_flags & PR_KLC)
482*0Sstevel@tonic-gate 		dt_proc_stop(dpr, DT_PROC_STOP_CREATE);
483*0Sstevel@tonic-gate 	else
484*0Sstevel@tonic-gate 		dt_proc_stop(dpr, DT_PROC_STOP_GRAB);
485*0Sstevel@tonic-gate 
486*0Sstevel@tonic-gate 	if (Psetrun(P, 0, 0) == -1) {
487*0Sstevel@tonic-gate 		dt_dprintf("pid %d: failed to set running: %s\n",
488*0Sstevel@tonic-gate 		    (int)dpr->dpr_pid, strerror(errno));
489*0Sstevel@tonic-gate 	}
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&dpr->dpr_lock);
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate 	/*
494*0Sstevel@tonic-gate 	 * Wait for the process corresponding to this control thread to stop,
495*0Sstevel@tonic-gate 	 * process the event, and then set it running again.  We want to sleep
496*0Sstevel@tonic-gate 	 * with dpr_lock *unheld* so that other parts of libdtrace can use the
497*0Sstevel@tonic-gate 	 * ps_prochandle in the meantime (e.g. ustack()).  To do this, we write
498*0Sstevel@tonic-gate 	 * a PCWSTOP directive directly to the underlying /proc/<pid>/ctl file.
499*0Sstevel@tonic-gate 	 * Once the process stops, we wake up, grab dpr_lock, and then call
500*0Sstevel@tonic-gate 	 * Pwait() (which will return immediately) and do our processing.
501*0Sstevel@tonic-gate 	 */
502*0Sstevel@tonic-gate 	while (!dpr->dpr_quit) {
503*0Sstevel@tonic-gate 		const lwpstatus_t *psp;
504*0Sstevel@tonic-gate 
505*0Sstevel@tonic-gate 		if (write(pfd, &wstop, sizeof (wstop)) == -1 && errno == EINTR)
506*0Sstevel@tonic-gate 			continue; /* check dpr_quit and continue waiting */
507*0Sstevel@tonic-gate 
508*0Sstevel@tonic-gate 		(void) pthread_mutex_lock(&dpr->dpr_lock);
509*0Sstevel@tonic-gate pwait_locked:
510*0Sstevel@tonic-gate 		if (Pstopstatus(P, PCNULL, 0) == -1 && errno == EINTR) {
511*0Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&dpr->dpr_lock);
512*0Sstevel@tonic-gate 			continue; /* check dpr_quit and continue waiting */
513*0Sstevel@tonic-gate 		}
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate 		switch (Pstate(P)) {
516*0Sstevel@tonic-gate 		case PS_STOP:
517*0Sstevel@tonic-gate 			psp = &Pstatus(P)->pr_lwp;
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate 			dt_dprintf("pid %d: proc stopped showing %d/%d\n",
520*0Sstevel@tonic-gate 			    pid, psp->pr_why, psp->pr_what);
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate 			/*
523*0Sstevel@tonic-gate 			 * If the process stops showing PR_REQUESTED, then the
524*0Sstevel@tonic-gate 			 * DTrace stop() action was applied to it or another
525*0Sstevel@tonic-gate 			 * debugging utility (e.g. pstop(1)) asked it to stop.
526*0Sstevel@tonic-gate 			 * In either case, the user's intention is for the
527*0Sstevel@tonic-gate 			 * process to remain stopped until another external
528*0Sstevel@tonic-gate 			 * mechanism (e.g. prun(1)) is applied.  So instead of
529*0Sstevel@tonic-gate 			 * setting the process running ourself, we wait for
530*0Sstevel@tonic-gate 			 * someone else to do so.  Once that happens, we return
531*0Sstevel@tonic-gate 			 * to our normal loop waiting for an event of interest.
532*0Sstevel@tonic-gate 			 */
533*0Sstevel@tonic-gate 			if (psp->pr_why == PR_REQUESTED) {
534*0Sstevel@tonic-gate 				dt_proc_waitrun(dpr);
535*0Sstevel@tonic-gate 				(void) pthread_mutex_unlock(&dpr->dpr_lock);
536*0Sstevel@tonic-gate 				continue;
537*0Sstevel@tonic-gate 			}
538*0Sstevel@tonic-gate 
539*0Sstevel@tonic-gate 			/*
540*0Sstevel@tonic-gate 			 * If the process stops showing one of the events that
541*0Sstevel@tonic-gate 			 * we are tracing, perform the appropriate response.
542*0Sstevel@tonic-gate 			 * Note that we ignore PR_SUSPENDED, PR_CHECKPOINT, and
543*0Sstevel@tonic-gate 			 * PR_JOBCONTROL by design: if one of these conditions
544*0Sstevel@tonic-gate 			 * occurs, we will fall through to Psetrun() but the
545*0Sstevel@tonic-gate 			 * process will remain stopped in the kernel by the
546*0Sstevel@tonic-gate 			 * corresponding mechanism (e.g. job control stop).
547*0Sstevel@tonic-gate 			 */
548*0Sstevel@tonic-gate 			if (psp->pr_why == PR_FAULTED && psp->pr_what == FLTBPT)
549*0Sstevel@tonic-gate 				dt_proc_bpmatch(dtp, dpr);
550*0Sstevel@tonic-gate 			else if (psp->pr_why == PR_SYSENTRY &&
551*0Sstevel@tonic-gate 			    IS_SYS_FORK(psp->pr_what))
552*0Sstevel@tonic-gate 				dt_proc_bpdisable(dpr);
553*0Sstevel@tonic-gate 			else if (psp->pr_why == PR_SYSEXIT &&
554*0Sstevel@tonic-gate 			    IS_SYS_FORK(psp->pr_what))
555*0Sstevel@tonic-gate 				dt_proc_bpenable(dpr);
556*0Sstevel@tonic-gate 			else if (psp->pr_why == PR_SYSEXIT &&
557*0Sstevel@tonic-gate 			    IS_SYS_EXEC(psp->pr_what))
558*0Sstevel@tonic-gate 				dt_proc_attach(dpr, B_TRUE);
559*0Sstevel@tonic-gate 			break;
560*0Sstevel@tonic-gate 
561*0Sstevel@tonic-gate 		case PS_LOST:
562*0Sstevel@tonic-gate 			if (Preopen(P) == 0)
563*0Sstevel@tonic-gate 				goto pwait_locked;
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate 			dt_dprintf("pid %d: proc lost: %s\n",
566*0Sstevel@tonic-gate 			    pid, strerror(errno));
567*0Sstevel@tonic-gate 
568*0Sstevel@tonic-gate 			dpr->dpr_quit = B_TRUE;
569*0Sstevel@tonic-gate 			notify = B_TRUE;
570*0Sstevel@tonic-gate 			break;
571*0Sstevel@tonic-gate 
572*0Sstevel@tonic-gate 		case PS_UNDEAD:
573*0Sstevel@tonic-gate 			dt_dprintf("pid %d: proc died\n", pid);
574*0Sstevel@tonic-gate 			dpr->dpr_quit = B_TRUE;
575*0Sstevel@tonic-gate 			notify = B_TRUE;
576*0Sstevel@tonic-gate 			break;
577*0Sstevel@tonic-gate 		}
578*0Sstevel@tonic-gate 
579*0Sstevel@tonic-gate 		if (Pstate(P) != PS_UNDEAD && Psetrun(P, 0, 0) == -1) {
580*0Sstevel@tonic-gate 			dt_dprintf("pid %d: failed to set running: %s\n",
581*0Sstevel@tonic-gate 			    (int)dpr->dpr_pid, strerror(errno));
582*0Sstevel@tonic-gate 		}
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&dpr->dpr_lock);
585*0Sstevel@tonic-gate 	}
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate 	/*
588*0Sstevel@tonic-gate 	 * If the control thread detected PS_UNDEAD or PS_LOST, then enqueue
589*0Sstevel@tonic-gate 	 * the dt_proc_t structure on the dt_proc_hash_t notification list.
590*0Sstevel@tonic-gate 	 */
591*0Sstevel@tonic-gate 	if (notify) {
592*0Sstevel@tonic-gate 		(void) pthread_mutex_lock(&dph->dph_lock);
593*0Sstevel@tonic-gate 
594*0Sstevel@tonic-gate 		dpr->dpr_notify = dph->dph_notify;
595*0Sstevel@tonic-gate 		dph->dph_notify = dpr;
596*0Sstevel@tonic-gate 
597*0Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&dph->dph_lock);
598*0Sstevel@tonic-gate 		(void) pthread_cond_broadcast(&dph->dph_cv);
599*0Sstevel@tonic-gate 	}
600*0Sstevel@tonic-gate 
601*0Sstevel@tonic-gate 	/*
602*0Sstevel@tonic-gate 	 * Destroy and remove any remaining breakpoints, set dpr_done and clear
603*0Sstevel@tonic-gate 	 * dpr_tid to indicate the control thread has exited, and notify any
604*0Sstevel@tonic-gate 	 * waiting thread in dt_proc_destroy() that we have succesfully exited.
605*0Sstevel@tonic-gate 	 */
606*0Sstevel@tonic-gate 	(void) pthread_mutex_lock(&dpr->dpr_lock);
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate 	dt_proc_bpdestroy(dpr, B_TRUE);
609*0Sstevel@tonic-gate 	dpr->dpr_done = B_TRUE;
610*0Sstevel@tonic-gate 	dpr->dpr_tid = 0;
611*0Sstevel@tonic-gate 
612*0Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&dpr->dpr_lock);
613*0Sstevel@tonic-gate 	(void) pthread_cond_broadcast(&dpr->dpr_cv);
614*0Sstevel@tonic-gate 
615*0Sstevel@tonic-gate 	return (NULL);
616*0Sstevel@tonic-gate }
617*0Sstevel@tonic-gate 
618*0Sstevel@tonic-gate /*PRINTFLIKE3*/
619*0Sstevel@tonic-gate static struct ps_prochandle *
620*0Sstevel@tonic-gate dt_proc_error(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *format, ...)
621*0Sstevel@tonic-gate {
622*0Sstevel@tonic-gate 	va_list ap;
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate 	va_start(ap, format);
625*0Sstevel@tonic-gate 	dt_set_errmsg(dtp, NULL, NULL, NULL, 0, format, ap);
626*0Sstevel@tonic-gate 	va_end(ap);
627*0Sstevel@tonic-gate 
628*0Sstevel@tonic-gate 	if (dpr->dpr_proc != NULL)
629*0Sstevel@tonic-gate 		Prelease(dpr->dpr_proc, 0);
630*0Sstevel@tonic-gate 
631*0Sstevel@tonic-gate 	dt_free(dtp, dpr);
632*0Sstevel@tonic-gate 	(void) dt_set_errno(dtp, EDT_COMPILER);
633*0Sstevel@tonic-gate 	return (NULL);
634*0Sstevel@tonic-gate }
635*0Sstevel@tonic-gate 
636*0Sstevel@tonic-gate dt_proc_t *
637*0Sstevel@tonic-gate dt_proc_lookup(dtrace_hdl_t *dtp, struct ps_prochandle *P, int remove)
638*0Sstevel@tonic-gate {
639*0Sstevel@tonic-gate 	dt_proc_hash_t *dph = dtp->dt_procs;
640*0Sstevel@tonic-gate 	pid_t pid = Pstatus(P)->pr_pid;
641*0Sstevel@tonic-gate 	dt_proc_t *dpr, **dpp = &dph->dph_hash[pid & (dph->dph_hashlen - 1)];
642*0Sstevel@tonic-gate 
643*0Sstevel@tonic-gate 	for (dpr = *dpp; dpr != NULL; dpr = dpr->dpr_hash) {
644*0Sstevel@tonic-gate 		if (dpr->dpr_pid == pid)
645*0Sstevel@tonic-gate 			break;
646*0Sstevel@tonic-gate 		else
647*0Sstevel@tonic-gate 			dpp = &dpr->dpr_hash;
648*0Sstevel@tonic-gate 	}
649*0Sstevel@tonic-gate 
650*0Sstevel@tonic-gate 	assert(dpr != NULL);
651*0Sstevel@tonic-gate 	assert(dpr->dpr_proc == P);
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 	if (remove)
654*0Sstevel@tonic-gate 		*dpp = dpr->dpr_hash; /* remove from pid hash chain */
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate 	return (dpr);
657*0Sstevel@tonic-gate }
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate static void
660*0Sstevel@tonic-gate dt_proc_destroy(dtrace_hdl_t *dtp, struct ps_prochandle *P)
661*0Sstevel@tonic-gate {
662*0Sstevel@tonic-gate 	dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_TRUE);
663*0Sstevel@tonic-gate 	dt_proc_hash_t *dph = dtp->dt_procs;
664*0Sstevel@tonic-gate 	dt_proc_t *npr, **npp;
665*0Sstevel@tonic-gate 	int rflag;
666*0Sstevel@tonic-gate 
667*0Sstevel@tonic-gate 	assert(dpr != NULL);
668*0Sstevel@tonic-gate 
669*0Sstevel@tonic-gate 	/*
670*0Sstevel@tonic-gate 	 * If neither PR_KLC nor PR_RLC is set, then the process is stopped by
671*0Sstevel@tonic-gate 	 * an external debugger and we were waiting in dt_proc_waitrun().
672*0Sstevel@tonic-gate 	 * Leave the process in this condition using PRELEASE_HANG.
673*0Sstevel@tonic-gate 	 */
674*0Sstevel@tonic-gate 	if (!(Pstatus(dpr->dpr_proc)->pr_flags & (PR_KLC | PR_RLC))) {
675*0Sstevel@tonic-gate 		dt_dprintf("abandoning pid %d\n", (int)dpr->dpr_pid);
676*0Sstevel@tonic-gate 		rflag = PRELEASE_HANG;
677*0Sstevel@tonic-gate 	} else {
678*0Sstevel@tonic-gate 		dt_dprintf("releasing pid %d\n", (int)dpr->dpr_pid);
679*0Sstevel@tonic-gate 		rflag = 0; /* apply kill or run-on-last-close */
680*0Sstevel@tonic-gate 	}
681*0Sstevel@tonic-gate 
682*0Sstevel@tonic-gate 	if (dpr->dpr_tid) {
683*0Sstevel@tonic-gate 		/*
684*0Sstevel@tonic-gate 		 * Set the dpr_quit flag to tell the daemon thread to exit.  We
685*0Sstevel@tonic-gate 		 * send it a SIGCANCEL to poke it out of PCWSTOP or any other
686*0Sstevel@tonic-gate 		 * long-term /proc system call.  Our daemon threads have POSIX
687*0Sstevel@tonic-gate 		 * cancellation disabled, so EINTR will be the only effect.  We
688*0Sstevel@tonic-gate 		 * then wait for dpr_done to indicate the thread has exited.
689*0Sstevel@tonic-gate 		 *
690*0Sstevel@tonic-gate 		 * We can't use pthread_kill() to send SIGCANCEL because the
691*0Sstevel@tonic-gate 		 * interface forbids it and we can't use pthread_cancel()
692*0Sstevel@tonic-gate 		 * because with cancellation disabled it won't actually
693*0Sstevel@tonic-gate 		 * send SIGCANCEL to the target thread, so we use _lwp_kill()
694*0Sstevel@tonic-gate 		 * to do the job.  This is all built on evil knowledge of
695*0Sstevel@tonic-gate 		 * the details of the cancellation mechanism in libc.
696*0Sstevel@tonic-gate 		 */
697*0Sstevel@tonic-gate 		(void) pthread_mutex_lock(&dpr->dpr_lock);
698*0Sstevel@tonic-gate 		dpr->dpr_quit = B_TRUE;
699*0Sstevel@tonic-gate 		(void) _lwp_kill(dpr->dpr_tid, SIGCANCEL);
700*0Sstevel@tonic-gate 
701*0Sstevel@tonic-gate 		while (!dpr->dpr_done)
702*0Sstevel@tonic-gate 			(void) pthread_cond_wait(&dpr->dpr_cv, &dpr->dpr_lock);
703*0Sstevel@tonic-gate 
704*0Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&dpr->dpr_lock);
705*0Sstevel@tonic-gate 	}
706*0Sstevel@tonic-gate 
707*0Sstevel@tonic-gate 	/*
708*0Sstevel@tonic-gate 	 * Before we free the process structure, walk the dt_proc_hash_t's
709*0Sstevel@tonic-gate 	 * notification list and remove this dt_proc_t if it is enqueued.
710*0Sstevel@tonic-gate 	 */
711*0Sstevel@tonic-gate 	(void) pthread_mutex_lock(&dph->dph_lock);
712*0Sstevel@tonic-gate 	npp = &dph->dph_notify;
713*0Sstevel@tonic-gate 
714*0Sstevel@tonic-gate 	for (npr = *npp; npr != NULL; npr = npr->dpr_notify) {
715*0Sstevel@tonic-gate 		if (npr != dpr)
716*0Sstevel@tonic-gate 			npp = &npr->dpr_notify;
717*0Sstevel@tonic-gate 		else
718*0Sstevel@tonic-gate 			break;
719*0Sstevel@tonic-gate 	}
720*0Sstevel@tonic-gate 
721*0Sstevel@tonic-gate 	if (npr != NULL) {
722*0Sstevel@tonic-gate 		*npp = npr->dpr_notify;
723*0Sstevel@tonic-gate 		npr->dpr_notify = NULL;
724*0Sstevel@tonic-gate 	}
725*0Sstevel@tonic-gate 
726*0Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&dph->dph_lock);
727*0Sstevel@tonic-gate 
728*0Sstevel@tonic-gate 	/*
729*0Sstevel@tonic-gate 	 * Remove the dt_proc_list from the LRU list, release the underlying
730*0Sstevel@tonic-gate 	 * libproc handle, and free our dt_proc_t data structure.
731*0Sstevel@tonic-gate 	 */
732*0Sstevel@tonic-gate 	if (dpr->dpr_cacheable) {
733*0Sstevel@tonic-gate 		assert(dph->dph_lrucnt != 0);
734*0Sstevel@tonic-gate 		dph->dph_lrucnt--;
735*0Sstevel@tonic-gate 	}
736*0Sstevel@tonic-gate 
737*0Sstevel@tonic-gate 	dt_list_delete(&dph->dph_lrulist, dpr);
738*0Sstevel@tonic-gate 	Prelease(dpr->dpr_proc, rflag);
739*0Sstevel@tonic-gate 	dt_free(dtp, dpr);
740*0Sstevel@tonic-gate }
741*0Sstevel@tonic-gate 
742*0Sstevel@tonic-gate static int
743*0Sstevel@tonic-gate dt_proc_create_thread(dtrace_hdl_t *dtp, dt_proc_t *dpr, uint_t stop)
744*0Sstevel@tonic-gate {
745*0Sstevel@tonic-gate 	dt_proc_control_data_t data;
746*0Sstevel@tonic-gate 	sigset_t nset, oset;
747*0Sstevel@tonic-gate 	pthread_attr_t a;
748*0Sstevel@tonic-gate 	int err;
749*0Sstevel@tonic-gate 
750*0Sstevel@tonic-gate 	(void) pthread_mutex_lock(&dpr->dpr_lock);
751*0Sstevel@tonic-gate 	dpr->dpr_stop |= stop; /* set bit for initial rendezvous */
752*0Sstevel@tonic-gate 
753*0Sstevel@tonic-gate 	(void) pthread_attr_init(&a);
754*0Sstevel@tonic-gate 	(void) pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED);
755*0Sstevel@tonic-gate 
756*0Sstevel@tonic-gate 	(void) sigfillset(&nset);
757*0Sstevel@tonic-gate 	(void) sigdelset(&nset, SIGABRT);	/* unblocked for assert() */
758*0Sstevel@tonic-gate 	(void) sigdelset(&nset, SIGCANCEL);	/* see dt_proc_destroy() */
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate 	data.dpcd_hdl = dtp;
761*0Sstevel@tonic-gate 	data.dpcd_proc = dpr;
762*0Sstevel@tonic-gate 
763*0Sstevel@tonic-gate 	(void) pthread_sigmask(SIG_SETMASK, &nset, &oset);
764*0Sstevel@tonic-gate 	err = pthread_create(&dpr->dpr_tid, &a, dt_proc_control, &data);
765*0Sstevel@tonic-gate 	(void) pthread_sigmask(SIG_SETMASK, &oset, NULL);
766*0Sstevel@tonic-gate 
767*0Sstevel@tonic-gate 	/*
768*0Sstevel@tonic-gate 	 * If the control thread was created, then wait on dpr_cv for either
769*0Sstevel@tonic-gate 	 * dpr_done to be set (the victim died or the control thread failed)
770*0Sstevel@tonic-gate 	 * or DT_PROC_STOP_IDLE to be set, indicating that the victim is now
771*0Sstevel@tonic-gate 	 * stopped by /proc and the control thread is at the rendezvous event.
772*0Sstevel@tonic-gate 	 * On success, we return with the process and control thread stopped:
773*0Sstevel@tonic-gate 	 * the caller can then apply dt_proc_continue() to resume both.
774*0Sstevel@tonic-gate 	 */
775*0Sstevel@tonic-gate 	if (err == 0) {
776*0Sstevel@tonic-gate 		while (!dpr->dpr_done && !(dpr->dpr_stop & DT_PROC_STOP_IDLE))
777*0Sstevel@tonic-gate 			(void) pthread_cond_wait(&dpr->dpr_cv, &dpr->dpr_lock);
778*0Sstevel@tonic-gate 
779*0Sstevel@tonic-gate 		/*
780*0Sstevel@tonic-gate 		 * If dpr_done is set, the control thread aborted before it
781*0Sstevel@tonic-gate 		 * reached the rendezvous event.  This is either due to PS_LOST
782*0Sstevel@tonic-gate 		 * or PS_UNDEAD (i.e. the process died).  We try to provide a
783*0Sstevel@tonic-gate 		 * small amount of useful information to help figure it out.
784*0Sstevel@tonic-gate 		 */
785*0Sstevel@tonic-gate 		if (dpr->dpr_done) {
786*0Sstevel@tonic-gate 			const psinfo_t *prp = Ppsinfo(dpr->dpr_proc);
787*0Sstevel@tonic-gate 			int stat = prp ? prp->pr_wstat : 0;
788*0Sstevel@tonic-gate 			int pid = dpr->dpr_pid;
789*0Sstevel@tonic-gate 
790*0Sstevel@tonic-gate 			if (Pstate(dpr->dpr_proc) == PS_LOST) {
791*0Sstevel@tonic-gate 				(void) dt_proc_error(dpr->dpr_hdl, dpr,
792*0Sstevel@tonic-gate 				    "failed to control pid %d: process exec'd "
793*0Sstevel@tonic-gate 				    "set-id or unobservable program\n", pid);
794*0Sstevel@tonic-gate 			} else if (WIFSIGNALED(stat)) {
795*0Sstevel@tonic-gate 				(void) dt_proc_error(dpr->dpr_hdl, dpr,
796*0Sstevel@tonic-gate 				    "failed to control pid %d: process died "
797*0Sstevel@tonic-gate 				    "from signal %d\n", pid, WTERMSIG(stat));
798*0Sstevel@tonic-gate 			} else {
799*0Sstevel@tonic-gate 				(void) dt_proc_error(dpr->dpr_hdl, dpr,
800*0Sstevel@tonic-gate 				    "failed to control pid %d: process exited "
801*0Sstevel@tonic-gate 				    "with status %d\n", pid, WEXITSTATUS(stat));
802*0Sstevel@tonic-gate 			}
803*0Sstevel@tonic-gate 
804*0Sstevel@tonic-gate 			err = ESRCH; /* cause grab() or create() to fail */
805*0Sstevel@tonic-gate 		} else {
806*0Sstevel@tonic-gate 			/*
807*0Sstevel@tonic-gate 			 * Disable breakpoints while the process is stopped so
808*0Sstevel@tonic-gate 			 * the pid provider can correctly disassemble all
809*0Sstevel@tonic-gate 			 * functions.
810*0Sstevel@tonic-gate 			 */
811*0Sstevel@tonic-gate 			dt_proc_bpdisable(dpr);
812*0Sstevel@tonic-gate 		}
813*0Sstevel@tonic-gate 
814*0Sstevel@tonic-gate 	} else {
815*0Sstevel@tonic-gate 		(void) dt_proc_error(dpr->dpr_hdl, dpr,
816*0Sstevel@tonic-gate 		    "failed to create control thread for process-id %d: %s\n",
817*0Sstevel@tonic-gate 		    (int)dpr->dpr_pid, strerror(err));
818*0Sstevel@tonic-gate 	}
819*0Sstevel@tonic-gate 
820*0Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&dpr->dpr_lock);
821*0Sstevel@tonic-gate 	(void) pthread_attr_destroy(&a);
822*0Sstevel@tonic-gate 
823*0Sstevel@tonic-gate 	return (err);
824*0Sstevel@tonic-gate }
825*0Sstevel@tonic-gate 
826*0Sstevel@tonic-gate struct ps_prochandle *
827*0Sstevel@tonic-gate dt_proc_create(dtrace_hdl_t *dtp, const char *file, char *const *argv)
828*0Sstevel@tonic-gate {
829*0Sstevel@tonic-gate 	dt_proc_hash_t *dph = dtp->dt_procs;
830*0Sstevel@tonic-gate 	dt_proc_t *dpr;
831*0Sstevel@tonic-gate 	int err;
832*0Sstevel@tonic-gate 
833*0Sstevel@tonic-gate 	if ((dpr = dt_zalloc(dtp, sizeof (dt_proc_t))) == NULL)
834*0Sstevel@tonic-gate 		return (NULL); /* errno is set for us */
835*0Sstevel@tonic-gate 
836*0Sstevel@tonic-gate 	(void) pthread_mutex_init(&dpr->dpr_lock, NULL);
837*0Sstevel@tonic-gate 	(void) pthread_cond_init(&dpr->dpr_cv, NULL);
838*0Sstevel@tonic-gate 
839*0Sstevel@tonic-gate 	if ((dpr->dpr_proc = Pcreate(file, argv, &err, NULL, 0)) == NULL) {
840*0Sstevel@tonic-gate 		return (dt_proc_error(dtp, dpr,
841*0Sstevel@tonic-gate 		    "failed to execute %s: %s\n", file, Pcreate_error(err)));
842*0Sstevel@tonic-gate 	}
843*0Sstevel@tonic-gate 
844*0Sstevel@tonic-gate 	dpr->dpr_hdl = dtp;
845*0Sstevel@tonic-gate 	dpr->dpr_pid = Pstatus(dpr->dpr_proc)->pr_pid;
846*0Sstevel@tonic-gate 
847*0Sstevel@tonic-gate 	(void) Punsetflags(dpr->dpr_proc, PR_RLC);
848*0Sstevel@tonic-gate 	(void) Psetflags(dpr->dpr_proc, PR_KLC);
849*0Sstevel@tonic-gate 
850*0Sstevel@tonic-gate 	if (dt_proc_create_thread(dtp, dpr, dtp->dt_prcmode) != 0)
851*0Sstevel@tonic-gate 		return (NULL); /* dt_proc_error() has been called for us */
852*0Sstevel@tonic-gate 
853*0Sstevel@tonic-gate 	dpr->dpr_hash = dph->dph_hash[dpr->dpr_pid & (dph->dph_hashlen - 1)];
854*0Sstevel@tonic-gate 	dph->dph_hash[dpr->dpr_pid & (dph->dph_hashlen - 1)] = dpr;
855*0Sstevel@tonic-gate 	dt_list_prepend(&dph->dph_lrulist, dpr);
856*0Sstevel@tonic-gate 
857*0Sstevel@tonic-gate 	dt_dprintf("created pid %d\n", (int)dpr->dpr_pid);
858*0Sstevel@tonic-gate 	dpr->dpr_refs++;
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate 	return (dpr->dpr_proc);
861*0Sstevel@tonic-gate }
862*0Sstevel@tonic-gate 
863*0Sstevel@tonic-gate struct ps_prochandle *
864*0Sstevel@tonic-gate dt_proc_grab(dtrace_hdl_t *dtp, pid_t pid, int flags, int nomonitor)
865*0Sstevel@tonic-gate {
866*0Sstevel@tonic-gate 	dt_proc_hash_t *dph = dtp->dt_procs;
867*0Sstevel@tonic-gate 	uint_t h = pid & (dph->dph_hashlen - 1);
868*0Sstevel@tonic-gate 	dt_proc_t *dpr, *opr;
869*0Sstevel@tonic-gate 	int err;
870*0Sstevel@tonic-gate 
871*0Sstevel@tonic-gate 	/*
872*0Sstevel@tonic-gate 	 * Search the hash table for the pid.  If it is already grabbed or
873*0Sstevel@tonic-gate 	 * created, move the handle to the front of the lrulist, increment
874*0Sstevel@tonic-gate 	 * the reference count, and return the existing ps_prochandle.
875*0Sstevel@tonic-gate 	 */
876*0Sstevel@tonic-gate 	for (dpr = dph->dph_hash[h]; dpr != NULL; dpr = dpr->dpr_hash) {
877*0Sstevel@tonic-gate 		if (dpr->dpr_pid == pid && !dpr->dpr_stale) {
878*0Sstevel@tonic-gate 			/*
879*0Sstevel@tonic-gate 			 * If the cached handle was opened read-only and
880*0Sstevel@tonic-gate 			 * this request is for a writeable handle, mark
881*0Sstevel@tonic-gate 			 * the cached handle as stale and open a new handle.
882*0Sstevel@tonic-gate 			 * Since it's stale, unmark it as cacheable.
883*0Sstevel@tonic-gate 			 */
884*0Sstevel@tonic-gate 			if (dpr->dpr_rdonly && !(flags & PGRAB_RDONLY)) {
885*0Sstevel@tonic-gate 				dt_dprintf("upgrading pid %d\n", (int)pid);
886*0Sstevel@tonic-gate 				dpr->dpr_stale = B_TRUE;
887*0Sstevel@tonic-gate 				dpr->dpr_cacheable = B_FALSE;
888*0Sstevel@tonic-gate 				dph->dph_lrucnt--;
889*0Sstevel@tonic-gate 				break;
890*0Sstevel@tonic-gate 			}
891*0Sstevel@tonic-gate 
892*0Sstevel@tonic-gate 			dt_dprintf("grabbed pid %d (cached)\n", (int)pid);
893*0Sstevel@tonic-gate 			dt_list_delete(&dph->dph_lrulist, dpr);
894*0Sstevel@tonic-gate 			dt_list_prepend(&dph->dph_lrulist, dpr);
895*0Sstevel@tonic-gate 			dpr->dpr_refs++;
896*0Sstevel@tonic-gate 			return (dpr->dpr_proc);
897*0Sstevel@tonic-gate 		}
898*0Sstevel@tonic-gate 	}
899*0Sstevel@tonic-gate 
900*0Sstevel@tonic-gate 	if ((dpr = dt_zalloc(dtp, sizeof (dt_proc_t))) == NULL)
901*0Sstevel@tonic-gate 		return (NULL); /* errno is set for us */
902*0Sstevel@tonic-gate 
903*0Sstevel@tonic-gate 	(void) pthread_mutex_init(&dpr->dpr_lock, NULL);
904*0Sstevel@tonic-gate 	(void) pthread_cond_init(&dpr->dpr_cv, NULL);
905*0Sstevel@tonic-gate 
906*0Sstevel@tonic-gate 	if ((dpr->dpr_proc = Pgrab(pid, flags, &err)) == NULL) {
907*0Sstevel@tonic-gate 		return (dt_proc_error(dtp, dpr,
908*0Sstevel@tonic-gate 		    "failed to grab pid %d: %s\n", (int)pid, Pgrab_error(err)));
909*0Sstevel@tonic-gate 	}
910*0Sstevel@tonic-gate 
911*0Sstevel@tonic-gate 	dpr->dpr_hdl = dtp;
912*0Sstevel@tonic-gate 	dpr->dpr_pid = pid;
913*0Sstevel@tonic-gate 
914*0Sstevel@tonic-gate 	(void) Punsetflags(dpr->dpr_proc, PR_KLC);
915*0Sstevel@tonic-gate 	(void) Psetflags(dpr->dpr_proc, PR_RLC);
916*0Sstevel@tonic-gate 
917*0Sstevel@tonic-gate 	/*
918*0Sstevel@tonic-gate 	 * If we are attempting to grab the process without a monitor
919*0Sstevel@tonic-gate 	 * thread, then mark the process cacheable only if it's being
920*0Sstevel@tonic-gate 	 * grabbed read-only.  If we're currently caching more process
921*0Sstevel@tonic-gate 	 * handles than dph_lrulim permits, attempt to find the
922*0Sstevel@tonic-gate 	 * least-recently-used handle that is currently unreferenced and
923*0Sstevel@tonic-gate 	 * release it from the cache.  Otherwise we are grabbing the process
924*0Sstevel@tonic-gate 	 * for control: create a control thread for this process and store
925*0Sstevel@tonic-gate 	 * its ID in dpr->dpr_tid.
926*0Sstevel@tonic-gate 	 */
927*0Sstevel@tonic-gate 	if (nomonitor || (flags & PGRAB_RDONLY)) {
928*0Sstevel@tonic-gate 		if (dph->dph_lrucnt >= dph->dph_lrulim) {
929*0Sstevel@tonic-gate 			for (opr = dt_list_prev(&dph->dph_lrulist);
930*0Sstevel@tonic-gate 			    opr != NULL; opr = dt_list_prev(opr)) {
931*0Sstevel@tonic-gate 				if (opr->dpr_cacheable && opr->dpr_refs == 0) {
932*0Sstevel@tonic-gate 					dt_proc_destroy(dtp, opr->dpr_proc);
933*0Sstevel@tonic-gate 					break;
934*0Sstevel@tonic-gate 				}
935*0Sstevel@tonic-gate 			}
936*0Sstevel@tonic-gate 		}
937*0Sstevel@tonic-gate 
938*0Sstevel@tonic-gate 		if (flags & PGRAB_RDONLY) {
939*0Sstevel@tonic-gate 			dpr->dpr_cacheable = B_TRUE;
940*0Sstevel@tonic-gate 			dpr->dpr_rdonly = B_TRUE;
941*0Sstevel@tonic-gate 			dph->dph_lrucnt++;
942*0Sstevel@tonic-gate 		}
943*0Sstevel@tonic-gate 
944*0Sstevel@tonic-gate 	} else if (dt_proc_create_thread(dtp, dpr, DT_PROC_STOP_GRAB) != 0)
945*0Sstevel@tonic-gate 		return (NULL); /* dt_proc_error() has been called for us */
946*0Sstevel@tonic-gate 
947*0Sstevel@tonic-gate 	dpr->dpr_hash = dph->dph_hash[h];
948*0Sstevel@tonic-gate 	dph->dph_hash[h] = dpr;
949*0Sstevel@tonic-gate 	dt_list_prepend(&dph->dph_lrulist, dpr);
950*0Sstevel@tonic-gate 
951*0Sstevel@tonic-gate 	dt_dprintf("grabbed pid %d\n", (int)pid);
952*0Sstevel@tonic-gate 	dpr->dpr_refs++;
953*0Sstevel@tonic-gate 
954*0Sstevel@tonic-gate 	return (dpr->dpr_proc);
955*0Sstevel@tonic-gate }
956*0Sstevel@tonic-gate 
957*0Sstevel@tonic-gate void
958*0Sstevel@tonic-gate dt_proc_release(dtrace_hdl_t *dtp, struct ps_prochandle *P)
959*0Sstevel@tonic-gate {
960*0Sstevel@tonic-gate 	dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE);
961*0Sstevel@tonic-gate 	dt_proc_hash_t *dph = dtp->dt_procs;
962*0Sstevel@tonic-gate 
963*0Sstevel@tonic-gate 	assert(dpr != NULL);
964*0Sstevel@tonic-gate 	assert(dpr->dpr_refs != 0);
965*0Sstevel@tonic-gate 
966*0Sstevel@tonic-gate 	if (--dpr->dpr_refs == 0 &&
967*0Sstevel@tonic-gate 	    (!dpr->dpr_cacheable || dph->dph_lrucnt > dph->dph_lrulim))
968*0Sstevel@tonic-gate 		dt_proc_destroy(dtp, P);
969*0Sstevel@tonic-gate }
970*0Sstevel@tonic-gate 
971*0Sstevel@tonic-gate void
972*0Sstevel@tonic-gate dt_proc_continue(dtrace_hdl_t *dtp, struct ps_prochandle *P)
973*0Sstevel@tonic-gate {
974*0Sstevel@tonic-gate 	dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE);
975*0Sstevel@tonic-gate 
976*0Sstevel@tonic-gate 	(void) pthread_mutex_lock(&dpr->dpr_lock);
977*0Sstevel@tonic-gate 
978*0Sstevel@tonic-gate 	if (dpr->dpr_stop & DT_PROC_STOP_IDLE) {
979*0Sstevel@tonic-gate 		/*
980*0Sstevel@tonic-gate 		 * Breakpoints are disabled while the process is stopped so
981*0Sstevel@tonic-gate 		 * the pid provider can correctly disassemble all functions.
982*0Sstevel@tonic-gate 		 */
983*0Sstevel@tonic-gate 		dt_proc_bpenable(dpr);
984*0Sstevel@tonic-gate 		dpr->dpr_stop &= ~DT_PROC_STOP_IDLE;
985*0Sstevel@tonic-gate 		(void) pthread_cond_broadcast(&dpr->dpr_cv);
986*0Sstevel@tonic-gate 	}
987*0Sstevel@tonic-gate 
988*0Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&dpr->dpr_lock);
989*0Sstevel@tonic-gate }
990*0Sstevel@tonic-gate 
991*0Sstevel@tonic-gate void
992*0Sstevel@tonic-gate dt_proc_lock(dtrace_hdl_t *dtp, struct ps_prochandle *P)
993*0Sstevel@tonic-gate {
994*0Sstevel@tonic-gate 	dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE);
995*0Sstevel@tonic-gate 	int err = pthread_mutex_lock(&dpr->dpr_lock);
996*0Sstevel@tonic-gate 	assert(err == 0); /* check for recursion */
997*0Sstevel@tonic-gate }
998*0Sstevel@tonic-gate 
999*0Sstevel@tonic-gate void
1000*0Sstevel@tonic-gate dt_proc_unlock(dtrace_hdl_t *dtp, struct ps_prochandle *P)
1001*0Sstevel@tonic-gate {
1002*0Sstevel@tonic-gate 	dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE);
1003*0Sstevel@tonic-gate 	int err = pthread_mutex_unlock(&dpr->dpr_lock);
1004*0Sstevel@tonic-gate 	assert(err == 0); /* check for unheld lock */
1005*0Sstevel@tonic-gate }
1006*0Sstevel@tonic-gate 
1007*0Sstevel@tonic-gate void
1008*0Sstevel@tonic-gate dt_proc_hash_create(dtrace_hdl_t *dtp)
1009*0Sstevel@tonic-gate {
1010*0Sstevel@tonic-gate 	if ((dtp->dt_procs = dt_zalloc(dtp, sizeof (dt_proc_hash_t) +
1011*0Sstevel@tonic-gate 	    sizeof (dt_proc_t *) * _dtrace_pidbuckets - 1)) != NULL) {
1012*0Sstevel@tonic-gate 
1013*0Sstevel@tonic-gate 		(void) pthread_mutex_init(&dtp->dt_procs->dph_lock, NULL);
1014*0Sstevel@tonic-gate 		(void) pthread_cond_init(&dtp->dt_procs->dph_cv, NULL);
1015*0Sstevel@tonic-gate 
1016*0Sstevel@tonic-gate 		dtp->dt_procs->dph_hashlen = _dtrace_pidbuckets;
1017*0Sstevel@tonic-gate 		dtp->dt_procs->dph_lrulim = _dtrace_pidlrulim;
1018*0Sstevel@tonic-gate 	}
1019*0Sstevel@tonic-gate }
1020*0Sstevel@tonic-gate 
1021*0Sstevel@tonic-gate void
1022*0Sstevel@tonic-gate dt_proc_hash_destroy(dtrace_hdl_t *dtp)
1023*0Sstevel@tonic-gate {
1024*0Sstevel@tonic-gate 	dt_proc_hash_t *dph = dtp->dt_procs;
1025*0Sstevel@tonic-gate 	dt_proc_t *dpr;
1026*0Sstevel@tonic-gate 
1027*0Sstevel@tonic-gate 	while ((dpr = dt_list_next(&dph->dph_lrulist)) != NULL)
1028*0Sstevel@tonic-gate 		dt_proc_destroy(dtp, dpr->dpr_proc);
1029*0Sstevel@tonic-gate 
1030*0Sstevel@tonic-gate 	dtp->dt_procs = NULL;
1031*0Sstevel@tonic-gate 	dt_free(dtp, dph);
1032*0Sstevel@tonic-gate }
1033*0Sstevel@tonic-gate 
1034*0Sstevel@tonic-gate struct ps_prochandle *
1035*0Sstevel@tonic-gate dtrace_proc_create(dtrace_hdl_t *dtp, const char *file, char *const *argv)
1036*0Sstevel@tonic-gate {
1037*0Sstevel@tonic-gate 	dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target");
1038*0Sstevel@tonic-gate 	struct ps_prochandle *P = dt_proc_create(dtp, file, argv);
1039*0Sstevel@tonic-gate 
1040*0Sstevel@tonic-gate 	if (P != NULL && idp != NULL && idp->di_id == 0)
1041*0Sstevel@tonic-gate 		idp->di_id = Pstatus(P)->pr_pid; /* $target = created pid */
1042*0Sstevel@tonic-gate 
1043*0Sstevel@tonic-gate 	return (P);
1044*0Sstevel@tonic-gate }
1045*0Sstevel@tonic-gate 
1046*0Sstevel@tonic-gate struct ps_prochandle *
1047*0Sstevel@tonic-gate dtrace_proc_grab(dtrace_hdl_t *dtp, pid_t pid, int flags)
1048*0Sstevel@tonic-gate {
1049*0Sstevel@tonic-gate 	dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target");
1050*0Sstevel@tonic-gate 	struct ps_prochandle *P = dt_proc_grab(dtp, pid, flags, 0);
1051*0Sstevel@tonic-gate 
1052*0Sstevel@tonic-gate 	if (P != NULL && idp != NULL && idp->di_id == 0)
1053*0Sstevel@tonic-gate 		idp->di_id = pid; /* $target = grabbed pid */
1054*0Sstevel@tonic-gate 
1055*0Sstevel@tonic-gate 	return (P);
1056*0Sstevel@tonic-gate }
1057*0Sstevel@tonic-gate 
1058*0Sstevel@tonic-gate void
1059*0Sstevel@tonic-gate dtrace_proc_release(dtrace_hdl_t *dtp, struct ps_prochandle *P)
1060*0Sstevel@tonic-gate {
1061*0Sstevel@tonic-gate 	dt_proc_release(dtp, P);
1062*0Sstevel@tonic-gate }
1063*0Sstevel@tonic-gate 
1064*0Sstevel@tonic-gate void
1065*0Sstevel@tonic-gate dtrace_proc_continue(dtrace_hdl_t *dtp, struct ps_prochandle *P)
1066*0Sstevel@tonic-gate {
1067*0Sstevel@tonic-gate 	dt_proc_continue(dtp, P);
1068*0Sstevel@tonic-gate }
1069