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