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