16ff6d951SJohn Birrell /*
26ff6d951SJohn Birrell * CDDL HEADER START
36ff6d951SJohn Birrell *
46ff6d951SJohn Birrell * The contents of this file are subject to the terms of the
56ff6d951SJohn Birrell * Common Development and Distribution License (the "License").
66ff6d951SJohn Birrell * You may not use this file except in compliance with the License.
76ff6d951SJohn Birrell *
86ff6d951SJohn Birrell * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96ff6d951SJohn Birrell * or http://www.opensolaris.org/os/licensing.
106ff6d951SJohn Birrell * See the License for the specific language governing permissions
116ff6d951SJohn Birrell * and limitations under the License.
126ff6d951SJohn Birrell *
136ff6d951SJohn Birrell * When distributing Covered Code, include this CDDL HEADER in each
146ff6d951SJohn Birrell * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156ff6d951SJohn Birrell * If applicable, add the following below this CDDL HEADER, with the
166ff6d951SJohn Birrell * fields enclosed by brackets "[]" replaced with your own identifying
176ff6d951SJohn Birrell * information: Portions Copyright [yyyy] [name of copyright owner]
186ff6d951SJohn Birrell *
196ff6d951SJohn Birrell * CDDL HEADER END
206ff6d951SJohn Birrell */
216ff6d951SJohn Birrell
226ff6d951SJohn Birrell /*
231670a1c2SRui Paulo * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
246ff6d951SJohn Birrell * Use is subject to license terms.
256ff6d951SJohn Birrell */
266ff6d951SJohn Birrell
276ff6d951SJohn Birrell /*
2804006780SMark Johnston * Copyright (c) 2012 by Delphix. All rights reserved.
2904006780SMark Johnston */
3004006780SMark Johnston
3104006780SMark Johnston /*
326ff6d951SJohn Birrell * DTrace Process Control
336ff6d951SJohn Birrell *
346ff6d951SJohn Birrell * This file provides a set of routines that permit libdtrace and its clients
356ff6d951SJohn Birrell * to create and grab process handles using libproc, and to share these handles
366ff6d951SJohn Birrell * between library mechanisms that need libproc access, such as ustack(), and
376ff6d951SJohn Birrell * client mechanisms that need libproc access, such as dtrace(1M) -c and -p.
386ff6d951SJohn Birrell * The library provides several mechanisms in the libproc control layer:
396ff6d951SJohn Birrell *
406ff6d951SJohn Birrell * Reference Counting: The library code and client code can independently grab
416ff6d951SJohn Birrell * the same process handles without interfering with one another. Only when
426ff6d951SJohn Birrell * the reference count drops to zero and the handle is not being cached (see
436ff6d951SJohn Birrell * below for more information on caching) will Prelease() be called on it.
446ff6d951SJohn Birrell *
456ff6d951SJohn Birrell * Handle Caching: If a handle is grabbed PGRAB_RDONLY (e.g. by ustack()) and
466ff6d951SJohn Birrell * the reference count drops to zero, the handle is not immediately released.
476ff6d951SJohn Birrell * Instead, libproc handles are maintained on dph_lrulist in order from most-
486ff6d951SJohn Birrell * recently accessed to least-recently accessed. Idle handles are maintained
496ff6d951SJohn Birrell * until a pre-defined LRU cache limit is exceeded, permitting repeated calls
506ff6d951SJohn Birrell * to ustack() to avoid the overhead of releasing and re-grabbing processes.
516ff6d951SJohn Birrell *
526ff6d951SJohn Birrell * Process Control: For processes that are grabbed for control (~PGRAB_RDONLY)
536ff6d951SJohn Birrell * or created by dt_proc_create(), a control thread is created to provide
546ff6d951SJohn Birrell * callbacks on process exit and symbol table caching on dlopen()s.
556ff6d951SJohn Birrell *
566ff6d951SJohn Birrell * MT-Safety: Libproc is not MT-Safe, so dt_proc_lock() and dt_proc_unlock()
576ff6d951SJohn Birrell * are provided to synchronize access to the libproc handle between libdtrace
586ff6d951SJohn Birrell * code and client code and the control thread's use of the ps_prochandle.
596ff6d951SJohn Birrell *
606ff6d951SJohn Birrell * NOTE: MT-Safety is NOT provided for libdtrace itself, or for use of the
616ff6d951SJohn Birrell * dtrace_proc_grab/dtrace_proc_create mechanisms. Like all exported libdtrace
626ff6d951SJohn Birrell * calls, these are assumed to be MT-Unsafe. MT-Safety is ONLY provided for
636ff6d951SJohn Birrell * synchronization between libdtrace control threads and the client thread.
646ff6d951SJohn Birrell *
656ff6d951SJohn Birrell * The ps_prochandles themselves are maintained along with a dt_proc_t struct
666ff6d951SJohn Birrell * in a hash table indexed by PID. This provides basic locking and reference
676ff6d951SJohn Birrell * counting. The dt_proc_t is also maintained in LRU order on dph_lrulist.
686ff6d951SJohn Birrell * The dph_lrucnt and dph_lrulim count the number of cacheable processes and
696ff6d951SJohn Birrell * the current limit on the number of actively cached entries.
706ff6d951SJohn Birrell *
716ff6d951SJohn Birrell * The control thread for a process establishes breakpoints at the rtld_db
726ff6d951SJohn Birrell * locations of interest, updates mappings and symbol tables at these points,
736ff6d951SJohn Birrell * and handles exec and fork (by always following the parent). The control
746ff6d951SJohn Birrell * thread automatically exits when the process dies or control is lost.
756ff6d951SJohn Birrell *
766ff6d951SJohn Birrell * A simple notification mechanism is provided for libdtrace clients using
776ff6d951SJohn Birrell * dtrace_handle_proc() for notification of PS_UNDEAD or PS_LOST events. If
786ff6d951SJohn Birrell * such an event occurs, the dt_proc_t itself is enqueued on a notification
796ff6d951SJohn Birrell * list and the control thread broadcasts to dph_cv. dtrace_sleep() will wake
806ff6d951SJohn Birrell * up using this condition and will then call the client handler as necessary.
816ff6d951SJohn Birrell */
826ff6d951SJohn Birrell
83837f6ecdSEric van Gyzen #include <sys/syscall.h>
846ff6d951SJohn Birrell #include <sys/wait.h>
856ff6d951SJohn Birrell #include <strings.h>
866ff6d951SJohn Birrell #include <signal.h>
876ff6d951SJohn Birrell #include <assert.h>
886ff6d951SJohn Birrell #include <errno.h>
896ff6d951SJohn Birrell
906ff6d951SJohn Birrell #include <dt_proc.h>
916ff6d951SJohn Birrell #include <dt_pid.h>
926ff6d951SJohn Birrell #include <dt_impl.h>
936ff6d951SJohn Birrell
940f2bd1e8SRui Paulo #include <libproc_compat.h>
950f2bd1e8SRui Paulo
961670a1c2SRui Paulo #define IS_SYS_EXEC(w) (w == SYS_execve)
97837f6ecdSEric van Gyzen #define IS_SYS_FORK(w) (w == SYS_vfork || w == SYS_fork)
986ff6d951SJohn Birrell
996ff6d951SJohn Birrell static dt_bkpt_t *
dt_proc_bpcreate(dt_proc_t * dpr,uintptr_t addr,dt_bkpt_f * func,void * data)1006ff6d951SJohn Birrell dt_proc_bpcreate(dt_proc_t *dpr, uintptr_t addr, dt_bkpt_f *func, void *data)
1016ff6d951SJohn Birrell {
1026ff6d951SJohn Birrell struct ps_prochandle *P = dpr->dpr_proc;
1036ff6d951SJohn Birrell dt_bkpt_t *dbp;
1046ff6d951SJohn Birrell
10531a396adSRui Paulo assert(DT_MUTEX_HELD(&dpr->dpr_lock));
1066ff6d951SJohn Birrell
1076ff6d951SJohn Birrell if ((dbp = dt_zalloc(dpr->dpr_hdl, sizeof (dt_bkpt_t))) != NULL) {
1086ff6d951SJohn Birrell dbp->dbp_func = func;
1096ff6d951SJohn Birrell dbp->dbp_data = data;
1106ff6d951SJohn Birrell dbp->dbp_addr = addr;
1116ff6d951SJohn Birrell
1126ff6d951SJohn Birrell if (Psetbkpt(P, dbp->dbp_addr, &dbp->dbp_instr) == 0)
1136ff6d951SJohn Birrell dbp->dbp_active = B_TRUE;
1146ff6d951SJohn Birrell
1156ff6d951SJohn Birrell dt_list_append(&dpr->dpr_bps, dbp);
1166ff6d951SJohn Birrell }
1176ff6d951SJohn Birrell
1186ff6d951SJohn Birrell return (dbp);
1196ff6d951SJohn Birrell }
1206ff6d951SJohn Birrell
1216ff6d951SJohn Birrell static void
dt_proc_bpdestroy(dt_proc_t * dpr,int delbkpts)1226ff6d951SJohn Birrell dt_proc_bpdestroy(dt_proc_t *dpr, int delbkpts)
1236ff6d951SJohn Birrell {
1246ff6d951SJohn Birrell int state = Pstate(dpr->dpr_proc);
1256ff6d951SJohn Birrell dt_bkpt_t *dbp, *nbp;
1266ff6d951SJohn Birrell
12731a396adSRui Paulo assert(DT_MUTEX_HELD(&dpr->dpr_lock));
1286ff6d951SJohn Birrell
1296ff6d951SJohn Birrell for (dbp = dt_list_next(&dpr->dpr_bps); dbp != NULL; dbp = nbp) {
1306ff6d951SJohn Birrell if (delbkpts && dbp->dbp_active &&
1316ff6d951SJohn Birrell state != PS_LOST && state != PS_UNDEAD) {
1326ff6d951SJohn Birrell (void) Pdelbkpt(dpr->dpr_proc,
1336ff6d951SJohn Birrell dbp->dbp_addr, dbp->dbp_instr);
1346ff6d951SJohn Birrell }
1356ff6d951SJohn Birrell nbp = dt_list_next(dbp);
1366ff6d951SJohn Birrell dt_list_delete(&dpr->dpr_bps, dbp);
1376ff6d951SJohn Birrell dt_free(dpr->dpr_hdl, dbp);
1386ff6d951SJohn Birrell }
1396ff6d951SJohn Birrell }
1406ff6d951SJohn Birrell
1416ff6d951SJohn Birrell static void
dt_proc_bpmatch(dtrace_hdl_t * dtp,dt_proc_t * dpr)1426ff6d951SJohn Birrell dt_proc_bpmatch(dtrace_hdl_t *dtp, dt_proc_t *dpr)
1436ff6d951SJohn Birrell {
1440f2bd1e8SRui Paulo unsigned long pc;
1456ff6d951SJohn Birrell dt_bkpt_t *dbp;
1466ff6d951SJohn Birrell
14731a396adSRui Paulo assert(DT_MUTEX_HELD(&dpr->dpr_lock));
1486ff6d951SJohn Birrell
1490f2bd1e8SRui Paulo proc_regget(dpr->dpr_proc, REG_PC, &pc);
1500f2bd1e8SRui Paulo proc_bkptregadj(&pc);
1510f2bd1e8SRui Paulo
1526ff6d951SJohn Birrell for (dbp = dt_list_next(&dpr->dpr_bps);
1536ff6d951SJohn Birrell dbp != NULL; dbp = dt_list_next(dbp)) {
1540f2bd1e8SRui Paulo if (pc == dbp->dbp_addr)
1550f2bd1e8SRui Paulo break;
1566ff6d951SJohn Birrell }
1576ff6d951SJohn Birrell
1586ff6d951SJohn Birrell if (dbp == NULL) {
1596ff6d951SJohn Birrell dt_dprintf("pid %d: spurious breakpoint wakeup for %lx\n",
1600f2bd1e8SRui Paulo (int)dpr->dpr_pid, pc);
1616ff6d951SJohn Birrell return;
1626ff6d951SJohn Birrell }
1636ff6d951SJohn Birrell
1646ff6d951SJohn Birrell dt_dprintf("pid %d: hit breakpoint at %lx (%lu)\n",
1656ff6d951SJohn Birrell (int)dpr->dpr_pid, (ulong_t)dbp->dbp_addr, ++dbp->dbp_hits);
1666ff6d951SJohn Birrell
1676ff6d951SJohn Birrell dbp->dbp_func(dtp, dpr, dbp->dbp_data);
1686ff6d951SJohn Birrell (void) Pxecbkpt(dpr->dpr_proc, dbp->dbp_instr);
1696ff6d951SJohn Birrell }
1706ff6d951SJohn Birrell
1716ff6d951SJohn Birrell static void
dt_proc_bpenable(dt_proc_t * dpr)1726ff6d951SJohn Birrell dt_proc_bpenable(dt_proc_t *dpr)
1736ff6d951SJohn Birrell {
1746ff6d951SJohn Birrell dt_bkpt_t *dbp;
1756ff6d951SJohn Birrell
17631a396adSRui Paulo assert(DT_MUTEX_HELD(&dpr->dpr_lock));
1776ff6d951SJohn Birrell
1786ff6d951SJohn Birrell for (dbp = dt_list_next(&dpr->dpr_bps);
1796ff6d951SJohn Birrell dbp != NULL; dbp = dt_list_next(dbp)) {
1806ff6d951SJohn Birrell if (!dbp->dbp_active && Psetbkpt(dpr->dpr_proc,
1816ff6d951SJohn Birrell dbp->dbp_addr, &dbp->dbp_instr) == 0)
1826ff6d951SJohn Birrell dbp->dbp_active = B_TRUE;
1836ff6d951SJohn Birrell }
1846ff6d951SJohn Birrell
1856ff6d951SJohn Birrell dt_dprintf("breakpoints enabled\n");
1866ff6d951SJohn Birrell }
1876ff6d951SJohn Birrell
1886ff6d951SJohn Birrell static void
dt_proc_bpdisable(dt_proc_t * dpr)1896ff6d951SJohn Birrell dt_proc_bpdisable(dt_proc_t *dpr)
1906ff6d951SJohn Birrell {
1916ff6d951SJohn Birrell dt_bkpt_t *dbp;
1926ff6d951SJohn Birrell
19331a396adSRui Paulo assert(DT_MUTEX_HELD(&dpr->dpr_lock));
1946ff6d951SJohn Birrell
1956ff6d951SJohn Birrell for (dbp = dt_list_next(&dpr->dpr_bps);
1966ff6d951SJohn Birrell dbp != NULL; dbp = dt_list_next(dbp)) {
1976ff6d951SJohn Birrell if (dbp->dbp_active && Pdelbkpt(dpr->dpr_proc,
1986ff6d951SJohn Birrell dbp->dbp_addr, dbp->dbp_instr) == 0)
1996ff6d951SJohn Birrell dbp->dbp_active = B_FALSE;
2006ff6d951SJohn Birrell }
2016ff6d951SJohn Birrell
2026ff6d951SJohn Birrell dt_dprintf("breakpoints disabled\n");
2036ff6d951SJohn Birrell }
2046ff6d951SJohn Birrell
2056ff6d951SJohn Birrell static void
dt_proc_notify(dtrace_hdl_t * dtp,dt_proc_hash_t * dph,dt_proc_t * dpr,const char * msg)2066ff6d951SJohn Birrell dt_proc_notify(dtrace_hdl_t *dtp, dt_proc_hash_t *dph, dt_proc_t *dpr,
2076ff6d951SJohn Birrell const char *msg)
2086ff6d951SJohn Birrell {
2096ff6d951SJohn Birrell dt_proc_notify_t *dprn = dt_alloc(dtp, sizeof (dt_proc_notify_t));
2106ff6d951SJohn Birrell
2116ff6d951SJohn Birrell if (dprn == NULL) {
2126ff6d951SJohn Birrell dt_dprintf("failed to allocate notification for %d %s\n",
2136ff6d951SJohn Birrell (int)dpr->dpr_pid, msg);
2146ff6d951SJohn Birrell } else {
2156ff6d951SJohn Birrell dprn->dprn_dpr = dpr;
2166ff6d951SJohn Birrell if (msg == NULL)
2176ff6d951SJohn Birrell dprn->dprn_errmsg[0] = '\0';
2186ff6d951SJohn Birrell else
2196ff6d951SJohn Birrell (void) strlcpy(dprn->dprn_errmsg, msg,
2206ff6d951SJohn Birrell sizeof (dprn->dprn_errmsg));
2216ff6d951SJohn Birrell
2226ff6d951SJohn Birrell (void) pthread_mutex_lock(&dph->dph_lock);
2236ff6d951SJohn Birrell
2246ff6d951SJohn Birrell dprn->dprn_next = dph->dph_notify;
2256ff6d951SJohn Birrell dph->dph_notify = dprn;
2266ff6d951SJohn Birrell
2276ff6d951SJohn Birrell (void) pthread_cond_broadcast(&dph->dph_cv);
2286ff6d951SJohn Birrell (void) pthread_mutex_unlock(&dph->dph_lock);
2296ff6d951SJohn Birrell }
2306ff6d951SJohn Birrell }
2316ff6d951SJohn Birrell
2326ff6d951SJohn Birrell /*
2336ff6d951SJohn Birrell * Check to see if the control thread was requested to stop when the victim
2346ff6d951SJohn Birrell * process reached a particular event (why) rather than continuing the victim.
2356ff6d951SJohn Birrell * If 'why' is set in the stop mask, we wait on dpr_cv for dt_proc_continue().
2366ff6d951SJohn Birrell * If 'why' is not set, this function returns immediately and does nothing.
2376ff6d951SJohn Birrell */
2386ff6d951SJohn Birrell static void
dt_proc_stop(dt_proc_t * dpr,uint8_t why)2396ff6d951SJohn Birrell dt_proc_stop(dt_proc_t *dpr, uint8_t why)
2406ff6d951SJohn Birrell {
24131a396adSRui Paulo assert(DT_MUTEX_HELD(&dpr->dpr_lock));
2426ff6d951SJohn Birrell assert(why != DT_PROC_STOP_IDLE);
2436ff6d951SJohn Birrell
2446ff6d951SJohn Birrell if (dpr->dpr_stop & why) {
2456ff6d951SJohn Birrell dpr->dpr_stop |= DT_PROC_STOP_IDLE;
2466ff6d951SJohn Birrell dpr->dpr_stop &= ~why;
2476ff6d951SJohn Birrell
2486ff6d951SJohn Birrell (void) pthread_cond_broadcast(&dpr->dpr_cv);
2496ff6d951SJohn Birrell
2506ff6d951SJohn Birrell /*
2516ff6d951SJohn Birrell * We disable breakpoints while stopped to preserve the
2526ff6d951SJohn Birrell * integrity of the program text for both our own disassembly
2536ff6d951SJohn Birrell * and that of the kernel.
2546ff6d951SJohn Birrell */
2556ff6d951SJohn Birrell dt_proc_bpdisable(dpr);
2566ff6d951SJohn Birrell
2576ff6d951SJohn Birrell while (dpr->dpr_stop & DT_PROC_STOP_IDLE)
2586ff6d951SJohn Birrell (void) pthread_cond_wait(&dpr->dpr_cv, &dpr->dpr_lock);
2596ff6d951SJohn Birrell
2606ff6d951SJohn Birrell dt_proc_bpenable(dpr);
2616ff6d951SJohn Birrell }
2626ff6d951SJohn Birrell }
2636ff6d951SJohn Birrell
2646ff6d951SJohn Birrell /*ARGSUSED*/
2656ff6d951SJohn Birrell static void
dt_proc_bpmain(dtrace_hdl_t * dtp,dt_proc_t * dpr,const char * fname)2666ff6d951SJohn Birrell dt_proc_bpmain(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *fname)
2676ff6d951SJohn Birrell {
2686ff6d951SJohn Birrell dt_dprintf("pid %d: breakpoint at %s()\n", (int)dpr->dpr_pid, fname);
2696ff6d951SJohn Birrell dt_proc_stop(dpr, DT_PROC_STOP_MAIN);
2706ff6d951SJohn Birrell }
2716ff6d951SJohn Birrell
2726ff6d951SJohn Birrell static void
dt_proc_rdevent(dtrace_hdl_t * dtp,dt_proc_t * dpr,const char * evname)2736ff6d951SJohn Birrell dt_proc_rdevent(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *evname)
2746ff6d951SJohn Birrell {
2756ff6d951SJohn Birrell rd_event_msg_t rdm;
2766ff6d951SJohn Birrell rd_err_e err;
2776ff6d951SJohn Birrell
2786ff6d951SJohn Birrell if ((err = rd_event_getmsg(dpr->dpr_rtld, &rdm)) != RD_OK) {
2796ff6d951SJohn Birrell dt_dprintf("pid %d: failed to get %s event message: %s\n",
2806ff6d951SJohn Birrell (int)dpr->dpr_pid, evname, rd_errstr(err));
2816ff6d951SJohn Birrell return;
2826ff6d951SJohn Birrell }
2836ff6d951SJohn Birrell
2846ff6d951SJohn Birrell dt_dprintf("pid %d: rtld event %s type=%d state %d\n",
2856ff6d951SJohn Birrell (int)dpr->dpr_pid, evname, rdm.type, rdm.u.state);
2866ff6d951SJohn Birrell
2876ff6d951SJohn Birrell switch (rdm.type) {
2886ff6d951SJohn Birrell case RD_DLACTIVITY:
2896ff6d951SJohn Birrell if (rdm.u.state != RD_CONSISTENT)
2906ff6d951SJohn Birrell break;
2916ff6d951SJohn Birrell
2926ff6d951SJohn Birrell Pupdate_syms(dpr->dpr_proc);
2936ff6d951SJohn Birrell if (dt_pid_create_probes_module(dtp, dpr) != 0)
2946ff6d951SJohn Birrell dt_proc_notify(dtp, dtp->dt_procs, dpr,
2956ff6d951SJohn Birrell dpr->dpr_errmsg);
2966ff6d951SJohn Birrell
2976ff6d951SJohn Birrell break;
2986ff6d951SJohn Birrell case RD_PREINIT:
2996ff6d951SJohn Birrell Pupdate_syms(dpr->dpr_proc);
3006ff6d951SJohn Birrell dt_proc_stop(dpr, DT_PROC_STOP_PREINIT);
3016ff6d951SJohn Birrell break;
3026ff6d951SJohn Birrell case RD_POSTINIT:
3036ff6d951SJohn Birrell Pupdate_syms(dpr->dpr_proc);
3046ff6d951SJohn Birrell dt_proc_stop(dpr, DT_PROC_STOP_POSTINIT);
3056ff6d951SJohn Birrell break;
3066ff6d951SJohn Birrell }
3076ff6d951SJohn Birrell }
3086ff6d951SJohn Birrell
3096ff6d951SJohn Birrell static void
dt_proc_rdwatch(dt_proc_t * dpr,rd_event_e event,const char * evname)3106ff6d951SJohn Birrell dt_proc_rdwatch(dt_proc_t *dpr, rd_event_e event, const char *evname)
3116ff6d951SJohn Birrell {
3126ff6d951SJohn Birrell rd_notify_t rdn;
3136ff6d951SJohn Birrell rd_err_e err;
3146ff6d951SJohn Birrell
3156ff6d951SJohn Birrell if ((err = rd_event_addr(dpr->dpr_rtld, event, &rdn)) != RD_OK) {
3166ff6d951SJohn Birrell dt_dprintf("pid %d: failed to get event address for %s: %s\n",
3176ff6d951SJohn Birrell (int)dpr->dpr_pid, evname, rd_errstr(err));
3186ff6d951SJohn Birrell return;
3196ff6d951SJohn Birrell }
3206ff6d951SJohn Birrell
3216ff6d951SJohn Birrell if (rdn.type != RD_NOTIFY_BPT) {
3226ff6d951SJohn Birrell dt_dprintf("pid %d: event %s has unexpected type %d\n",
3236ff6d951SJohn Birrell (int)dpr->dpr_pid, evname, rdn.type);
3246ff6d951SJohn Birrell return;
3256ff6d951SJohn Birrell }
3266ff6d951SJohn Birrell
3276ff6d951SJohn Birrell (void) dt_proc_bpcreate(dpr, rdn.u.bptaddr,
3280f2bd1e8SRui Paulo /* XXX ugly */
3290f2bd1e8SRui Paulo (dt_bkpt_f *)dt_proc_rdevent, __DECONST(void *, evname));
3306ff6d951SJohn Birrell }
3316ff6d951SJohn Birrell
3326ff6d951SJohn Birrell /*
3336ff6d951SJohn Birrell * Common code for enabling events associated with the run-time linker after
3346ff6d951SJohn Birrell * attaching to a process or after a victim process completes an exec(2).
3356ff6d951SJohn Birrell */
3366ff6d951SJohn Birrell static void
dt_proc_attach(dt_proc_t * dpr,int exec)3376ff6d951SJohn Birrell dt_proc_attach(dt_proc_t *dpr, int exec)
3386ff6d951SJohn Birrell {
3396ff6d951SJohn Birrell rd_err_e err;
3406ff6d951SJohn Birrell GElf_Sym sym;
3416ff6d951SJohn Birrell
34231a396adSRui Paulo assert(DT_MUTEX_HELD(&dpr->dpr_lock));
3436ff6d951SJohn Birrell
3446ff6d951SJohn Birrell if (exec) {
3456ff6d951SJohn Birrell
3466ff6d951SJohn Birrell dt_proc_bpdestroy(dpr, B_FALSE);
3476ff6d951SJohn Birrell }
3486ff6d951SJohn Birrell if ((dpr->dpr_rtld = Prd_agent(dpr->dpr_proc)) != NULL &&
3496ff6d951SJohn Birrell (err = rd_event_enable(dpr->dpr_rtld, B_TRUE)) == RD_OK) {
3506ff6d951SJohn Birrell dt_proc_rdwatch(dpr, RD_POSTINIT, "RD_POSTINIT");
3516ff6d951SJohn Birrell } else {
3526ff6d951SJohn Birrell dt_dprintf("pid %d: failed to enable rtld events: %s\n",
3536ff6d951SJohn Birrell (int)dpr->dpr_pid, dpr->dpr_rtld ? rd_errstr(err) :
3546ff6d951SJohn Birrell "rtld_db agent initialization failed");
3556ff6d951SJohn Birrell }
3566ff6d951SJohn Birrell
3576ff6d951SJohn Birrell Pupdate_maps(dpr->dpr_proc);
3586ff6d951SJohn Birrell
3596ff6d951SJohn Birrell if (Pxlookup_by_name(dpr->dpr_proc, LM_ID_BASE,
3606ff6d951SJohn Birrell "a.out", "main", &sym, NULL) == 0) {
3616ff6d951SJohn Birrell (void) dt_proc_bpcreate(dpr, (uintptr_t)sym.st_value,
3626ff6d951SJohn Birrell (dt_bkpt_f *)dt_proc_bpmain, "a.out`main");
3636ff6d951SJohn Birrell } else {
3646ff6d951SJohn Birrell dt_dprintf("pid %d: failed to find a.out`main: %s\n",
3656ff6d951SJohn Birrell (int)dpr->dpr_pid, strerror(errno));
3666ff6d951SJohn Birrell }
3676ff6d951SJohn Birrell }
3686ff6d951SJohn Birrell
3696ff6d951SJohn Birrell typedef struct dt_proc_control_data {
3706ff6d951SJohn Birrell dtrace_hdl_t *dpcd_hdl; /* DTrace handle */
3716ff6d951SJohn Birrell dt_proc_t *dpcd_proc; /* proccess to control */
3726ff6d951SJohn Birrell } dt_proc_control_data_t;
3736ff6d951SJohn Birrell
3746ff6d951SJohn Birrell /*
3756ff6d951SJohn Birrell * Main loop for all victim process control threads. We initialize all the
3766ff6d951SJohn Birrell * appropriate /proc control mechanisms, and then enter a loop waiting for
3776ff6d951SJohn Birrell * the process to stop on an event or die. We process any events by calling
3786ff6d951SJohn Birrell * appropriate subroutines, and exit when the victim dies or we lose control.
3796ff6d951SJohn Birrell *
3806ff6d951SJohn Birrell * The control thread synchronizes the use of dpr_proc with other libdtrace
3816ff6d951SJohn Birrell * threads using dpr_lock. We hold the lock for all of our operations except
3826ff6d951SJohn Birrell * waiting while the process is running: this is accomplished by writing a
3836ff6d951SJohn Birrell * PCWSTOP directive directly to the underlying /proc/<pid>/ctl file. If the
3846ff6d951SJohn Birrell * libdtrace client wishes to exit or abort our wait, SIGCANCEL can be used.
3856ff6d951SJohn Birrell */
3866ff6d951SJohn Birrell static void *
dt_proc_control(void * arg)3876ff6d951SJohn Birrell dt_proc_control(void *arg)
3886ff6d951SJohn Birrell {
3896ff6d951SJohn Birrell dt_proc_control_data_t *datap = arg;
3906ff6d951SJohn Birrell dtrace_hdl_t *dtp = datap->dpcd_hdl;
3916ff6d951SJohn Birrell dt_proc_t *dpr = datap->dpcd_proc;
39204006780SMark Johnston dt_proc_hash_t *dph = dtp->dt_procs;
3936ff6d951SJohn Birrell struct ps_prochandle *P = dpr->dpr_proc;
3946ff6d951SJohn Birrell int pid = dpr->dpr_pid;
3956ff6d951SJohn Birrell int notify = B_FALSE;
3966ff6d951SJohn Birrell
3976ff6d951SJohn Birrell /*
3986ff6d951SJohn Birrell * We disable the POSIX thread cancellation mechanism so that the
3996ff6d951SJohn Birrell * client program using libdtrace can't accidentally cancel our thread.
4006ff6d951SJohn Birrell * dt_proc_destroy() uses SIGCANCEL explicitly to simply poke us out
4016ff6d951SJohn Birrell * of PCWSTOP with EINTR, at which point we will see dpr_quit and exit.
4026ff6d951SJohn Birrell */
4036ff6d951SJohn Birrell (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
4046ff6d951SJohn Birrell
4056ff6d951SJohn Birrell /*
4066ff6d951SJohn Birrell * Set up the corresponding process for tracing by libdtrace. We want
4076ff6d951SJohn Birrell * to be able to catch breakpoints and efficiently single-step over
4086ff6d951SJohn Birrell * them, and we need to enable librtld_db to watch libdl activity.
4096ff6d951SJohn Birrell */
4106ff6d951SJohn Birrell (void) pthread_mutex_lock(&dpr->dpr_lock);
4116ff6d951SJohn Birrell
4126ff6d951SJohn Birrell dt_proc_attach(dpr, B_FALSE); /* enable rtld breakpoints */
4136ff6d951SJohn Birrell
4146ff6d951SJohn Birrell /*
415*bcbce2a2SEric van Gyzen * If DT_CLOSE_KILL is set, we created the process; otherwise we
416*bcbce2a2SEric van Gyzen * grabbed it. Check for an appropriate stop request and wait for
417*bcbce2a2SEric van Gyzen * dt_proc_continue.
4186ff6d951SJohn Birrell */
419*bcbce2a2SEric van Gyzen if (dpr->dpr_close == DT_CLOSE_KILL)
4206ff6d951SJohn Birrell dt_proc_stop(dpr, DT_PROC_STOP_CREATE);
4216ff6d951SJohn Birrell else
4226ff6d951SJohn Birrell dt_proc_stop(dpr, DT_PROC_STOP_GRAB);
4236ff6d951SJohn Birrell
4246ff6d951SJohn Birrell if (Psetrun(P, 0, 0) == -1) {
4256ff6d951SJohn Birrell dt_dprintf("pid %d: failed to set running: %s\n",
4266ff6d951SJohn Birrell (int)dpr->dpr_pid, strerror(errno));
4276ff6d951SJohn Birrell }
4286ff6d951SJohn Birrell
4296ff6d951SJohn Birrell (void) pthread_mutex_unlock(&dpr->dpr_lock);
4306ff6d951SJohn Birrell
4316ff6d951SJohn Birrell /*
4326ff6d951SJohn Birrell * Wait for the process corresponding to this control thread to stop,
4336ff6d951SJohn Birrell * process the event, and then set it running again. We want to sleep
4346ff6d951SJohn Birrell * with dpr_lock *unheld* so that other parts of libdtrace can use the
4356ff6d951SJohn Birrell * ps_prochandle in the meantime (e.g. ustack()). To do this, we write
4366ff6d951SJohn Birrell * a PCWSTOP directive directly to the underlying /proc/<pid>/ctl file.
4376ff6d951SJohn Birrell * Once the process stops, we wake up, grab dpr_lock, and then call
4386ff6d951SJohn Birrell * Pwait() (which will return immediately) and do our processing.
4396ff6d951SJohn Birrell */
4406ff6d951SJohn Birrell while (!dpr->dpr_quit) {
4416ff6d951SJohn Birrell const lwpstatus_t *psp;
4426ff6d951SJohn Birrell
443bbda5851SJohn Birrell /* Wait for the process to report status. */
4441e634b7bSRui Paulo proc_wstatus(P);
4450f2bd1e8SRui Paulo if (errno == EINTR)
4460f2bd1e8SRui Paulo continue; /* check dpr_quit and continue waiting */
4476ff6d951SJohn Birrell
4486ff6d951SJohn Birrell (void) pthread_mutex_lock(&dpr->dpr_lock);
449bbda5851SJohn Birrell
4506ff6d951SJohn Birrell switch (Pstate(P)) {
4516ff6d951SJohn Birrell case PS_STOP:
4520f2bd1e8SRui Paulo psp = proc_getlwpstatus(P);
4536ff6d951SJohn Birrell
4546ff6d951SJohn Birrell dt_dprintf("pid %d: proc stopped showing %d/%d\n",
4556ff6d951SJohn Birrell pid, psp->pr_why, psp->pr_what);
4566ff6d951SJohn Birrell
4576ff6d951SJohn Birrell /*
4586ff6d951SJohn Birrell * If the process stops showing one of the events that
4596ff6d951SJohn Birrell * we are tracing, perform the appropriate response.
4606ff6d951SJohn Birrell * Note that we ignore PR_SUSPENDED, PR_CHECKPOINT, and
4616ff6d951SJohn Birrell * PR_JOBCONTROL by design: if one of these conditions
4626ff6d951SJohn Birrell * occurs, we will fall through to Psetrun() but the
4636ff6d951SJohn Birrell * process will remain stopped in the kernel by the
4646ff6d951SJohn Birrell * corresponding mechanism (e.g. job control stop).
4656ff6d951SJohn Birrell */
4666ff6d951SJohn Birrell if (psp->pr_why == PR_FAULTED && psp->pr_what == FLTBPT)
4676ff6d951SJohn Birrell dt_proc_bpmatch(dtp, dpr);
4686ff6d951SJohn Birrell else if (psp->pr_why == PR_SYSENTRY &&
4696ff6d951SJohn Birrell IS_SYS_FORK(psp->pr_what))
4706ff6d951SJohn Birrell dt_proc_bpdisable(dpr);
4716ff6d951SJohn Birrell else if (psp->pr_why == PR_SYSEXIT &&
4726ff6d951SJohn Birrell IS_SYS_FORK(psp->pr_what))
4736ff6d951SJohn Birrell dt_proc_bpenable(dpr);
4746ff6d951SJohn Birrell else if (psp->pr_why == PR_SYSEXIT &&
4756ff6d951SJohn Birrell IS_SYS_EXEC(psp->pr_what))
4766ff6d951SJohn Birrell dt_proc_attach(dpr, B_TRUE);
4776ff6d951SJohn Birrell break;
4786ff6d951SJohn Birrell
4796ff6d951SJohn Birrell case PS_LOST:
4806ff6d951SJohn Birrell dt_dprintf("pid %d: proc lost: %s\n",
4816ff6d951SJohn Birrell pid, strerror(errno));
4826ff6d951SJohn Birrell
4836ff6d951SJohn Birrell dpr->dpr_quit = B_TRUE;
4846ff6d951SJohn Birrell notify = B_TRUE;
4856ff6d951SJohn Birrell break;
4866ff6d951SJohn Birrell
4876ff6d951SJohn Birrell case PS_UNDEAD:
4886ff6d951SJohn Birrell dt_dprintf("pid %d: proc died\n", pid);
4896ff6d951SJohn Birrell dpr->dpr_quit = B_TRUE;
4906ff6d951SJohn Birrell notify = B_TRUE;
4916ff6d951SJohn Birrell break;
4926ff6d951SJohn Birrell }
4936ff6d951SJohn Birrell
494dad11f99SEric van Gyzen if (Pstate(P) != PS_UNDEAD) {
495*bcbce2a2SEric van Gyzen if (dpr->dpr_quit && dpr->dpr_close == DT_CLOSE_KILL) {
496dad11f99SEric van Gyzen /*
497dad11f99SEric van Gyzen * We're about to kill the child, so don't
498dad11f99SEric van Gyzen * bother resuming it. In some cases, such as
499dad11f99SEric van Gyzen * an initialization error, we shouldn't have
500dad11f99SEric van Gyzen * started it in the first place, so letting it
501dad11f99SEric van Gyzen * run could be harmful.
502dad11f99SEric van Gyzen */
503dad11f99SEric van Gyzen } else if (Psetrun(P, 0, 0) == -1) {
504dad11f99SEric van Gyzen dt_dprintf("pid %d: failed to set running: "
505dad11f99SEric van Gyzen "%s\n", (int)dpr->dpr_pid, strerror(errno));
506dad11f99SEric van Gyzen }
5076ff6d951SJohn Birrell }
5086ff6d951SJohn Birrell
5096ff6d951SJohn Birrell (void) pthread_mutex_unlock(&dpr->dpr_lock);
5106ff6d951SJohn Birrell }
5116ff6d951SJohn Birrell
5126ff6d951SJohn Birrell /*
5136ff6d951SJohn Birrell * If the control thread detected PS_UNDEAD or PS_LOST, then enqueue
5146ff6d951SJohn Birrell * the dt_proc_t structure on the dt_proc_hash_t notification list.
5156ff6d951SJohn Birrell */
5166ff6d951SJohn Birrell if (notify)
5176ff6d951SJohn Birrell dt_proc_notify(dtp, dph, dpr, NULL);
5186ff6d951SJohn Birrell
5196ff6d951SJohn Birrell /*
5206ff6d951SJohn Birrell * Destroy and remove any remaining breakpoints, set dpr_done and clear
5216ff6d951SJohn Birrell * dpr_tid to indicate the control thread has exited, and notify any
5226ff6d951SJohn Birrell * waiting thread in dt_proc_destroy() that we have succesfully exited.
5236ff6d951SJohn Birrell */
5246ff6d951SJohn Birrell (void) pthread_mutex_lock(&dpr->dpr_lock);
5256ff6d951SJohn Birrell
5266ff6d951SJohn Birrell dt_proc_bpdestroy(dpr, B_TRUE);
5276ff6d951SJohn Birrell dpr->dpr_done = B_TRUE;
5286ff6d951SJohn Birrell dpr->dpr_tid = 0;
5296ff6d951SJohn Birrell
5306ff6d951SJohn Birrell (void) pthread_cond_broadcast(&dpr->dpr_cv);
5316ff6d951SJohn Birrell (void) pthread_mutex_unlock(&dpr->dpr_lock);
5326ff6d951SJohn Birrell
5336ff6d951SJohn Birrell return (NULL);
5346ff6d951SJohn Birrell }
5356ff6d951SJohn Birrell
5366ff6d951SJohn Birrell /*PRINTFLIKE3*/
5376ff6d951SJohn Birrell static struct ps_prochandle *
dt_proc_error(dtrace_hdl_t * dtp,dt_proc_t * dpr,const char * format,...)5386ff6d951SJohn Birrell dt_proc_error(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *format, ...)
5396ff6d951SJohn Birrell {
5406ff6d951SJohn Birrell va_list ap;
5416ff6d951SJohn Birrell
5426ff6d951SJohn Birrell va_start(ap, format);
5436ff6d951SJohn Birrell dt_set_errmsg(dtp, NULL, NULL, NULL, 0, format, ap);
5446ff6d951SJohn Birrell va_end(ap);
5456ff6d951SJohn Birrell
5466ff6d951SJohn Birrell if (dpr->dpr_proc != NULL)
5476ff6d951SJohn Birrell Prelease(dpr->dpr_proc, 0);
5486ff6d951SJohn Birrell
5496ff6d951SJohn Birrell dt_free(dtp, dpr);
5506ff6d951SJohn Birrell (void) dt_set_errno(dtp, EDT_COMPILER);
5516ff6d951SJohn Birrell return (NULL);
5526ff6d951SJohn Birrell }
5536ff6d951SJohn Birrell
5546ff6d951SJohn Birrell dt_proc_t *
dt_proc_lookup(dtrace_hdl_t * dtp,struct ps_prochandle * P,int remove)5556ff6d951SJohn Birrell dt_proc_lookup(dtrace_hdl_t *dtp, struct ps_prochandle *P, int remove)
5566ff6d951SJohn Birrell {
5576ff6d951SJohn Birrell dt_proc_hash_t *dph = dtp->dt_procs;
558bbda5851SJohn Birrell pid_t pid = proc_getpid(P);
5596ff6d951SJohn Birrell dt_proc_t *dpr, **dpp = &dph->dph_hash[pid & (dph->dph_hashlen - 1)];
5606ff6d951SJohn Birrell
5616ff6d951SJohn Birrell for (dpr = *dpp; dpr != NULL; dpr = dpr->dpr_hash) {
5626ff6d951SJohn Birrell if (dpr->dpr_pid == pid)
5636ff6d951SJohn Birrell break;
5646ff6d951SJohn Birrell else
5656ff6d951SJohn Birrell dpp = &dpr->dpr_hash;
5666ff6d951SJohn Birrell }
5676ff6d951SJohn Birrell
5686ff6d951SJohn Birrell assert(dpr != NULL);
5696ff6d951SJohn Birrell assert(dpr->dpr_proc == P);
5706ff6d951SJohn Birrell
5716ff6d951SJohn Birrell if (remove)
5726ff6d951SJohn Birrell *dpp = dpr->dpr_hash; /* remove from pid hash chain */
5736ff6d951SJohn Birrell
5746ff6d951SJohn Birrell return (dpr);
5756ff6d951SJohn Birrell }
5766ff6d951SJohn Birrell
5776ff6d951SJohn Birrell static void
dt_proc_destroy(dtrace_hdl_t * dtp,struct ps_prochandle * P)5786ff6d951SJohn Birrell dt_proc_destroy(dtrace_hdl_t *dtp, struct ps_prochandle *P)
5796ff6d951SJohn Birrell {
5806ff6d951SJohn Birrell dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE);
5816ff6d951SJohn Birrell dt_proc_hash_t *dph = dtp->dt_procs;
5826ff6d951SJohn Birrell dt_proc_notify_t *npr, **npp;
5836ff6d951SJohn Birrell int rflag;
5846ff6d951SJohn Birrell
5856ff6d951SJohn Birrell assert(dpr != NULL);
5866ff6d951SJohn Birrell
587*bcbce2a2SEric van Gyzen switch (dpr->dpr_close) {
588*bcbce2a2SEric van Gyzen case DT_CLOSE_KILL:
5891670a1c2SRui Paulo dt_dprintf("killing pid %d\n", (int)dpr->dpr_pid);
590*bcbce2a2SEric van Gyzen rflag = PRELEASE_KILL;
591*bcbce2a2SEric van Gyzen break;
592*bcbce2a2SEric van Gyzen case DT_CLOSE_RUN:
5936ff6d951SJohn Birrell dt_dprintf("releasing pid %d\n", (int)dpr->dpr_pid);
594*bcbce2a2SEric van Gyzen rflag = 0;
595*bcbce2a2SEric van Gyzen break;
5966ff6d951SJohn Birrell }
5976ff6d951SJohn Birrell
5986ff6d951SJohn Birrell if (dpr->dpr_tid) {
5996ff6d951SJohn Birrell /*
6006ff6d951SJohn Birrell * Set the dpr_quit flag to tell the daemon thread to exit. We
6016ff6d951SJohn Birrell * send it a SIGCANCEL to poke it out of PCWSTOP or any other
6026ff6d951SJohn Birrell * long-term /proc system call. Our daemon threads have POSIX
6036ff6d951SJohn Birrell * cancellation disabled, so EINTR will be the only effect. We
6046ff6d951SJohn Birrell * then wait for dpr_done to indicate the thread has exited.
6056ff6d951SJohn Birrell *
6066ff6d951SJohn Birrell * We can't use pthread_kill() to send SIGCANCEL because the
6076ff6d951SJohn Birrell * interface forbids it and we can't use pthread_cancel()
6086ff6d951SJohn Birrell * because with cancellation disabled it won't actually
6096ff6d951SJohn Birrell * send SIGCANCEL to the target thread, so we use _lwp_kill()
6106ff6d951SJohn Birrell * to do the job. This is all built on evil knowledge of
6116ff6d951SJohn Birrell * the details of the cancellation mechanism in libc.
6126ff6d951SJohn Birrell */
6136ff6d951SJohn Birrell (void) pthread_mutex_lock(&dpr->dpr_lock);
6146ff6d951SJohn Birrell dpr->dpr_quit = B_TRUE;
61572cc304aSGeorge V. Neville-Neil pthread_kill(dpr->dpr_tid, SIGTHR);
6166ff6d951SJohn Birrell
6176ff6d951SJohn Birrell /*
6186ff6d951SJohn Birrell * If the process is currently idling in dt_proc_stop(), re-
6196ff6d951SJohn Birrell * enable breakpoints and poke it into running again.
6206ff6d951SJohn Birrell */
6216ff6d951SJohn Birrell if (dpr->dpr_stop & DT_PROC_STOP_IDLE) {
6226ff6d951SJohn Birrell dt_proc_bpenable(dpr);
6236ff6d951SJohn Birrell dpr->dpr_stop &= ~DT_PROC_STOP_IDLE;
6246ff6d951SJohn Birrell (void) pthread_cond_broadcast(&dpr->dpr_cv);
6256ff6d951SJohn Birrell }
6266ff6d951SJohn Birrell
6276ff6d951SJohn Birrell while (!dpr->dpr_done)
6286ff6d951SJohn Birrell (void) pthread_cond_wait(&dpr->dpr_cv, &dpr->dpr_lock);
6296ff6d951SJohn Birrell
6306ff6d951SJohn Birrell (void) pthread_mutex_unlock(&dpr->dpr_lock);
6316ff6d951SJohn Birrell }
6326ff6d951SJohn Birrell
6336ff6d951SJohn Birrell /*
6346ff6d951SJohn Birrell * Before we free the process structure, remove this dt_proc_t from the
6356ff6d951SJohn Birrell * lookup hash, and then walk the dt_proc_hash_t's notification list
6366ff6d951SJohn Birrell * and remove this dt_proc_t if it is enqueued.
6376ff6d951SJohn Birrell */
6386ff6d951SJohn Birrell (void) pthread_mutex_lock(&dph->dph_lock);
6396ff6d951SJohn Birrell (void) dt_proc_lookup(dtp, P, B_TRUE);
6406ff6d951SJohn Birrell npp = &dph->dph_notify;
6416ff6d951SJohn Birrell
6426ff6d951SJohn Birrell while ((npr = *npp) != NULL) {
6436ff6d951SJohn Birrell if (npr->dprn_dpr == dpr) {
6446ff6d951SJohn Birrell *npp = npr->dprn_next;
6456ff6d951SJohn Birrell dt_free(dtp, npr);
6466ff6d951SJohn Birrell } else {
6476ff6d951SJohn Birrell npp = &npr->dprn_next;
6486ff6d951SJohn Birrell }
6496ff6d951SJohn Birrell }
6506ff6d951SJohn Birrell
6516ff6d951SJohn Birrell (void) pthread_mutex_unlock(&dph->dph_lock);
6526ff6d951SJohn Birrell
6536ff6d951SJohn Birrell /*
6546ff6d951SJohn Birrell * Remove the dt_proc_list from the LRU list, release the underlying
6556ff6d951SJohn Birrell * libproc handle, and free our dt_proc_t data structure.
6566ff6d951SJohn Birrell */
6576ff6d951SJohn Birrell if (dpr->dpr_cacheable) {
6586ff6d951SJohn Birrell assert(dph->dph_lrucnt != 0);
6596ff6d951SJohn Birrell dph->dph_lrucnt--;
6606ff6d951SJohn Birrell }
6616ff6d951SJohn Birrell
6626ff6d951SJohn Birrell dt_list_delete(&dph->dph_lrulist, dpr);
6636ff6d951SJohn Birrell Prelease(dpr->dpr_proc, rflag);
6646ff6d951SJohn Birrell dt_free(dtp, dpr);
6656ff6d951SJohn Birrell }
6666ff6d951SJohn Birrell
6676ff6d951SJohn Birrell static int
dt_proc_create_thread(dtrace_hdl_t * dtp,dt_proc_t * dpr,uint_t stop)6686ff6d951SJohn Birrell dt_proc_create_thread(dtrace_hdl_t *dtp, dt_proc_t *dpr, uint_t stop)
6696ff6d951SJohn Birrell {
6706ff6d951SJohn Birrell dt_proc_control_data_t data;
6716ff6d951SJohn Birrell sigset_t nset, oset;
6726ff6d951SJohn Birrell pthread_attr_t a;
6736ff6d951SJohn Birrell int err;
6746ff6d951SJohn Birrell
6756ff6d951SJohn Birrell (void) pthread_mutex_lock(&dpr->dpr_lock);
6766ff6d951SJohn Birrell dpr->dpr_stop |= stop; /* set bit for initial rendezvous */
6776ff6d951SJohn Birrell
6786ff6d951SJohn Birrell (void) pthread_attr_init(&a);
6796ff6d951SJohn Birrell (void) pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED);
6806ff6d951SJohn Birrell
6816ff6d951SJohn Birrell (void) sigfillset(&nset);
6826ff6d951SJohn Birrell (void) sigdelset(&nset, SIGABRT); /* unblocked for assert() */
683bbda5851SJohn Birrell (void) sigdelset(&nset, SIGUSR1); /* see dt_proc_destroy() */
6846ff6d951SJohn Birrell
6856ff6d951SJohn Birrell data.dpcd_hdl = dtp;
6866ff6d951SJohn Birrell data.dpcd_proc = dpr;
6876ff6d951SJohn Birrell
6886ff6d951SJohn Birrell (void) pthread_sigmask(SIG_SETMASK, &nset, &oset);
6896ff6d951SJohn Birrell err = pthread_create(&dpr->dpr_tid, &a, dt_proc_control, &data);
6906ff6d951SJohn Birrell (void) pthread_sigmask(SIG_SETMASK, &oset, NULL);
6916ff6d951SJohn Birrell
6926ff6d951SJohn Birrell /*
6936ff6d951SJohn Birrell * If the control thread was created, then wait on dpr_cv for either
6946ff6d951SJohn Birrell * dpr_done to be set (the victim died or the control thread failed)
6956ff6d951SJohn Birrell * or DT_PROC_STOP_IDLE to be set, indicating that the victim is now
6966ff6d951SJohn Birrell * stopped by /proc and the control thread is at the rendezvous event.
6976ff6d951SJohn Birrell * On success, we return with the process and control thread stopped:
6986ff6d951SJohn Birrell * the caller can then apply dt_proc_continue() to resume both.
6996ff6d951SJohn Birrell */
7006ff6d951SJohn Birrell if (err == 0) {
7016ff6d951SJohn Birrell while (!dpr->dpr_done && !(dpr->dpr_stop & DT_PROC_STOP_IDLE))
7026ff6d951SJohn Birrell (void) pthread_cond_wait(&dpr->dpr_cv, &dpr->dpr_lock);
7036ff6d951SJohn Birrell
7046ff6d951SJohn Birrell /*
7056ff6d951SJohn Birrell * If dpr_done is set, the control thread aborted before it
7066ff6d951SJohn Birrell * reached the rendezvous event. This is either due to PS_LOST
7076ff6d951SJohn Birrell * or PS_UNDEAD (i.e. the process died). We try to provide a
7086ff6d951SJohn Birrell * small amount of useful information to help figure it out.
7096ff6d951SJohn Birrell */
7106ff6d951SJohn Birrell if (dpr->dpr_done) {
7110f2bd1e8SRui Paulo int stat = proc_getwstat(dpr->dpr_proc);
7120f2bd1e8SRui Paulo int pid = proc_getpid(dpr->dpr_proc);
7130f2bd1e8SRui Paulo if (proc_state(dpr->dpr_proc) == PS_LOST) {
7146ff6d951SJohn Birrell (void) dt_proc_error(dpr->dpr_hdl, dpr,
7156ff6d951SJohn Birrell "failed to control pid %d: process exec'd "
7166ff6d951SJohn Birrell "set-id or unobservable program\n", pid);
7176ff6d951SJohn Birrell } else if (WIFSIGNALED(stat)) {
7186ff6d951SJohn Birrell (void) dt_proc_error(dpr->dpr_hdl, dpr,
7196ff6d951SJohn Birrell "failed to control pid %d: process died "
7206ff6d951SJohn Birrell "from signal %d\n", pid, WTERMSIG(stat));
7216ff6d951SJohn Birrell } else {
7226ff6d951SJohn Birrell (void) dt_proc_error(dpr->dpr_hdl, dpr,
7236ff6d951SJohn Birrell "failed to control pid %d: process exited "
7246ff6d951SJohn Birrell "with status %d\n", pid, WEXITSTATUS(stat));
7256ff6d951SJohn Birrell }
7266ff6d951SJohn Birrell
7276ff6d951SJohn Birrell err = ESRCH; /* cause grab() or create() to fail */
7286ff6d951SJohn Birrell }
7296ff6d951SJohn Birrell } else {
7306ff6d951SJohn Birrell (void) dt_proc_error(dpr->dpr_hdl, dpr,
7316ff6d951SJohn Birrell "failed to create control thread for process-id %d: %s\n",
7326ff6d951SJohn Birrell (int)dpr->dpr_pid, strerror(err));
7336ff6d951SJohn Birrell }
7346ff6d951SJohn Birrell
73526d121f5SGeorge V. Neville-Neil if (err == 0)
7366ff6d951SJohn Birrell (void) pthread_mutex_unlock(&dpr->dpr_lock);
7376ff6d951SJohn Birrell (void) pthread_attr_destroy(&a);
7386ff6d951SJohn Birrell
7396ff6d951SJohn Birrell return (err);
7406ff6d951SJohn Birrell }
7416ff6d951SJohn Birrell
7426ff6d951SJohn Birrell struct ps_prochandle *
dt_proc_create(dtrace_hdl_t * dtp,const char * file,char * const * argv,proc_child_func * pcf,void * child_arg)74356b35563SCraig Rodrigues dt_proc_create(dtrace_hdl_t *dtp, const char *file, char *const *argv,
74456b35563SCraig Rodrigues proc_child_func *pcf, void *child_arg)
7456ff6d951SJohn Birrell {
7466ff6d951SJohn Birrell dt_proc_hash_t *dph = dtp->dt_procs;
7476ff6d951SJohn Birrell dt_proc_t *dpr;
7486ff6d951SJohn Birrell int err;
7496ff6d951SJohn Birrell
7506ff6d951SJohn Birrell if ((dpr = dt_zalloc(dtp, sizeof (dt_proc_t))) == NULL)
7516ff6d951SJohn Birrell return (NULL); /* errno is set for us */
7526ff6d951SJohn Birrell
7536ff6d951SJohn Birrell (void) pthread_mutex_init(&dpr->dpr_lock, NULL);
7546ff6d951SJohn Birrell (void) pthread_cond_init(&dpr->dpr_cv, NULL);
7556ff6d951SJohn Birrell
75604006780SMark Johnston if ((err = proc_create(file, argv, dtp->dt_proc_env, pcf, child_arg,
75704006780SMark Johnston &dpr->dpr_proc)) != 0) {
75804006780SMark Johnston return (dt_proc_error(dtp, dpr,
75904006780SMark Johnston "failed to execute %s: %s\n", file, Pcreate_error(err)));
76004006780SMark Johnston }
7616ff6d951SJohn Birrell
7626ff6d951SJohn Birrell dpr->dpr_hdl = dtp;
763bbda5851SJohn Birrell dpr->dpr_pid = proc_getpid(dpr->dpr_proc);
764*bcbce2a2SEric van Gyzen dpr->dpr_close = DT_CLOSE_KILL;
7650f2bd1e8SRui Paulo
7666ff6d951SJohn Birrell if (dt_proc_create_thread(dtp, dpr, dtp->dt_prcmode) != 0)
7676ff6d951SJohn Birrell return (NULL); /* dt_proc_error() has been called for us */
7686ff6d951SJohn Birrell
7696ff6d951SJohn Birrell dpr->dpr_hash = dph->dph_hash[dpr->dpr_pid & (dph->dph_hashlen - 1)];
7706ff6d951SJohn Birrell dph->dph_hash[dpr->dpr_pid & (dph->dph_hashlen - 1)] = dpr;
7716ff6d951SJohn Birrell dt_list_prepend(&dph->dph_lrulist, dpr);
7726ff6d951SJohn Birrell
7736ff6d951SJohn Birrell dt_dprintf("created pid %d\n", (int)dpr->dpr_pid);
7746ff6d951SJohn Birrell dpr->dpr_refs++;
7756ff6d951SJohn Birrell
7766ff6d951SJohn Birrell return (dpr->dpr_proc);
7776ff6d951SJohn Birrell }
7786ff6d951SJohn Birrell
7796ff6d951SJohn Birrell struct ps_prochandle *
dt_proc_grab(dtrace_hdl_t * dtp,pid_t pid,int flags,int nomonitor)7806ff6d951SJohn Birrell dt_proc_grab(dtrace_hdl_t *dtp, pid_t pid, int flags, int nomonitor)
7816ff6d951SJohn Birrell {
7826ff6d951SJohn Birrell dt_proc_hash_t *dph = dtp->dt_procs;
7836ff6d951SJohn Birrell uint_t h = pid & (dph->dph_hashlen - 1);
7846ff6d951SJohn Birrell dt_proc_t *dpr, *opr;
7856ff6d951SJohn Birrell int err;
7866ff6d951SJohn Birrell
7876ff6d951SJohn Birrell /*
7886ff6d951SJohn Birrell * Search the hash table for the pid. If it is already grabbed or
7896ff6d951SJohn Birrell * created, move the handle to the front of the lrulist, increment
7906ff6d951SJohn Birrell * the reference count, and return the existing ps_prochandle.
7916ff6d951SJohn Birrell */
7926ff6d951SJohn Birrell for (dpr = dph->dph_hash[h]; dpr != NULL; dpr = dpr->dpr_hash) {
7936ff6d951SJohn Birrell if (dpr->dpr_pid == pid && !dpr->dpr_stale) {
7946ff6d951SJohn Birrell /*
7956ff6d951SJohn Birrell * If the cached handle was opened read-only and
7966ff6d951SJohn Birrell * this request is for a writeable handle, mark
7976ff6d951SJohn Birrell * the cached handle as stale and open a new handle.
7986ff6d951SJohn Birrell * Since it's stale, unmark it as cacheable.
7996ff6d951SJohn Birrell */
8006ff6d951SJohn Birrell if (dpr->dpr_rdonly && !(flags & PGRAB_RDONLY)) {
8016ff6d951SJohn Birrell dt_dprintf("upgrading pid %d\n", (int)pid);
8026ff6d951SJohn Birrell dpr->dpr_stale = B_TRUE;
8036ff6d951SJohn Birrell dpr->dpr_cacheable = B_FALSE;
8046ff6d951SJohn Birrell dph->dph_lrucnt--;
8056ff6d951SJohn Birrell break;
8066ff6d951SJohn Birrell }
8076ff6d951SJohn Birrell
8086ff6d951SJohn Birrell dt_dprintf("grabbed pid %d (cached)\n", (int)pid);
8096ff6d951SJohn Birrell dt_list_delete(&dph->dph_lrulist, dpr);
8106ff6d951SJohn Birrell dt_list_prepend(&dph->dph_lrulist, dpr);
8116ff6d951SJohn Birrell dpr->dpr_refs++;
8126ff6d951SJohn Birrell return (dpr->dpr_proc);
8136ff6d951SJohn Birrell }
8146ff6d951SJohn Birrell }
8156ff6d951SJohn Birrell
8166ff6d951SJohn Birrell if ((dpr = dt_zalloc(dtp, sizeof (dt_proc_t))) == NULL)
8176ff6d951SJohn Birrell return (NULL); /* errno is set for us */
8186ff6d951SJohn Birrell
8196ff6d951SJohn Birrell (void) pthread_mutex_init(&dpr->dpr_lock, NULL);
8206ff6d951SJohn Birrell (void) pthread_cond_init(&dpr->dpr_cv, NULL);
8216ff6d951SJohn Birrell
8220f2bd1e8SRui Paulo if ((err = proc_attach(pid, flags, &dpr->dpr_proc)) != 0) {
8236ff6d951SJohn Birrell return (dt_proc_error(dtp, dpr,
8246ff6d951SJohn Birrell "failed to grab pid %d: %s\n", (int)pid, Pgrab_error(err)));
8256ff6d951SJohn Birrell }
8266ff6d951SJohn Birrell
8276ff6d951SJohn Birrell dpr->dpr_hdl = dtp;
8286ff6d951SJohn Birrell dpr->dpr_pid = pid;
829*bcbce2a2SEric van Gyzen dpr->dpr_close = DT_CLOSE_RUN;
8306ff6d951SJohn Birrell
8316ff6d951SJohn Birrell /*
8326ff6d951SJohn Birrell * If we are attempting to grab the process without a monitor
8336ff6d951SJohn Birrell * thread, then mark the process cacheable only if it's being
8346ff6d951SJohn Birrell * grabbed read-only. If we're currently caching more process
8356ff6d951SJohn Birrell * handles than dph_lrulim permits, attempt to find the
8366ff6d951SJohn Birrell * least-recently-used handle that is currently unreferenced and
8376ff6d951SJohn Birrell * release it from the cache. Otherwise we are grabbing the process
8386ff6d951SJohn Birrell * for control: create a control thread for this process and store
8396ff6d951SJohn Birrell * its ID in dpr->dpr_tid.
8406ff6d951SJohn Birrell */
8416ff6d951SJohn Birrell if (nomonitor || (flags & PGRAB_RDONLY)) {
8426ff6d951SJohn Birrell if (dph->dph_lrucnt >= dph->dph_lrulim) {
8436ff6d951SJohn Birrell for (opr = dt_list_prev(&dph->dph_lrulist);
8446ff6d951SJohn Birrell opr != NULL; opr = dt_list_prev(opr)) {
8456ff6d951SJohn Birrell if (opr->dpr_cacheable && opr->dpr_refs == 0) {
8466ff6d951SJohn Birrell dt_proc_destroy(dtp, opr->dpr_proc);
8476ff6d951SJohn Birrell break;
8486ff6d951SJohn Birrell }
8496ff6d951SJohn Birrell }
8506ff6d951SJohn Birrell }
8516ff6d951SJohn Birrell
8526ff6d951SJohn Birrell if (flags & PGRAB_RDONLY) {
8536ff6d951SJohn Birrell dpr->dpr_cacheable = B_TRUE;
8546ff6d951SJohn Birrell dpr->dpr_rdonly = B_TRUE;
8556ff6d951SJohn Birrell dph->dph_lrucnt++;
8566ff6d951SJohn Birrell }
8576ff6d951SJohn Birrell
8586ff6d951SJohn Birrell } else if (dt_proc_create_thread(dtp, dpr, DT_PROC_STOP_GRAB) != 0)
8596ff6d951SJohn Birrell return (NULL); /* dt_proc_error() has been called for us */
8606ff6d951SJohn Birrell
8616ff6d951SJohn Birrell dpr->dpr_hash = dph->dph_hash[h];
8626ff6d951SJohn Birrell dph->dph_hash[h] = dpr;
8636ff6d951SJohn Birrell dt_list_prepend(&dph->dph_lrulist, dpr);
8646ff6d951SJohn Birrell
8656ff6d951SJohn Birrell dt_dprintf("grabbed pid %d\n", (int)pid);
8666ff6d951SJohn Birrell dpr->dpr_refs++;
8676ff6d951SJohn Birrell
8686ff6d951SJohn Birrell return (dpr->dpr_proc);
8696ff6d951SJohn Birrell }
8706ff6d951SJohn Birrell
8716ff6d951SJohn Birrell void
dt_proc_release(dtrace_hdl_t * dtp,struct ps_prochandle * P)8726ff6d951SJohn Birrell dt_proc_release(dtrace_hdl_t *dtp, struct ps_prochandle *P)
8736ff6d951SJohn Birrell {
8746ff6d951SJohn Birrell dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE);
8756ff6d951SJohn Birrell dt_proc_hash_t *dph = dtp->dt_procs;
8766ff6d951SJohn Birrell
8776ff6d951SJohn Birrell assert(dpr != NULL);
8786ff6d951SJohn Birrell assert(dpr->dpr_refs != 0);
8796ff6d951SJohn Birrell
8806ff6d951SJohn Birrell if (--dpr->dpr_refs == 0 &&
8816ff6d951SJohn Birrell (!dpr->dpr_cacheable || dph->dph_lrucnt > dph->dph_lrulim))
8826ff6d951SJohn Birrell dt_proc_destroy(dtp, P);
8836ff6d951SJohn Birrell }
8846ff6d951SJohn Birrell
8856ff6d951SJohn Birrell void
dt_proc_continue(dtrace_hdl_t * dtp,struct ps_prochandle * P)8866ff6d951SJohn Birrell dt_proc_continue(dtrace_hdl_t *dtp, struct ps_prochandle *P)
8876ff6d951SJohn Birrell {
8886ff6d951SJohn Birrell dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE);
8896ff6d951SJohn Birrell
8906ff6d951SJohn Birrell (void) pthread_mutex_lock(&dpr->dpr_lock);
8916ff6d951SJohn Birrell
8926ff6d951SJohn Birrell if (dpr->dpr_stop & DT_PROC_STOP_IDLE) {
8936ff6d951SJohn Birrell dpr->dpr_stop &= ~DT_PROC_STOP_IDLE;
8946ff6d951SJohn Birrell (void) pthread_cond_broadcast(&dpr->dpr_cv);
8956ff6d951SJohn Birrell }
8966ff6d951SJohn Birrell
8976ff6d951SJohn Birrell (void) pthread_mutex_unlock(&dpr->dpr_lock);
8986ff6d951SJohn Birrell }
8996ff6d951SJohn Birrell
9006ff6d951SJohn Birrell void
dt_proc_lock(dtrace_hdl_t * dtp,struct ps_prochandle * P)9016ff6d951SJohn Birrell dt_proc_lock(dtrace_hdl_t *dtp, struct ps_prochandle *P)
9026ff6d951SJohn Birrell {
9036ff6d951SJohn Birrell dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE);
9046ff6d951SJohn Birrell int err = pthread_mutex_lock(&dpr->dpr_lock);
9056ff6d951SJohn Birrell assert(err == 0); /* check for recursion */
9066ff6d951SJohn Birrell }
9076ff6d951SJohn Birrell
9086ff6d951SJohn Birrell void
dt_proc_unlock(dtrace_hdl_t * dtp,struct ps_prochandle * P)9096ff6d951SJohn Birrell dt_proc_unlock(dtrace_hdl_t *dtp, struct ps_prochandle *P)
9106ff6d951SJohn Birrell {
9116ff6d951SJohn Birrell dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE);
9126ff6d951SJohn Birrell int err = pthread_mutex_unlock(&dpr->dpr_lock);
9136ff6d951SJohn Birrell assert(err == 0); /* check for unheld lock */
9146ff6d951SJohn Birrell }
9156ff6d951SJohn Birrell
9166ff6d951SJohn Birrell void
dt_proc_init(dtrace_hdl_t * dtp)91704006780SMark Johnston dt_proc_init(dtrace_hdl_t *dtp)
9186ff6d951SJohn Birrell {
91904006780SMark Johnston extern char **environ;
92004006780SMark Johnston static char *envdef[] = {
92104006780SMark Johnston "LD_NOLAZYLOAD=1", /* linker lazy loading hides funcs */
92204006780SMark Johnston NULL
92304006780SMark Johnston };
92404006780SMark Johnston char **p;
92504006780SMark Johnston int i;
92604006780SMark Johnston
9276ff6d951SJohn Birrell if ((dtp->dt_procs = dt_zalloc(dtp, sizeof (dt_proc_hash_t) +
92804006780SMark Johnston sizeof (dt_proc_t *) * _dtrace_pidbuckets - 1)) == NULL)
92904006780SMark Johnston return;
9306ff6d951SJohn Birrell
9316ff6d951SJohn Birrell (void) pthread_mutex_init(&dtp->dt_procs->dph_lock, NULL);
9326ff6d951SJohn Birrell (void) pthread_cond_init(&dtp->dt_procs->dph_cv, NULL);
9336ff6d951SJohn Birrell
9346ff6d951SJohn Birrell dtp->dt_procs->dph_hashlen = _dtrace_pidbuckets;
9356ff6d951SJohn Birrell dtp->dt_procs->dph_lrulim = _dtrace_pidlrulim;
93604006780SMark Johnston
93704006780SMark Johnston /*
93804006780SMark Johnston * Count how big our environment needs to be.
93904006780SMark Johnston */
94004006780SMark Johnston for (i = 1, p = environ; *p != NULL; i++, p++)
94104006780SMark Johnston continue;
94204006780SMark Johnston for (p = envdef; *p != NULL; i++, p++)
94304006780SMark Johnston continue;
94404006780SMark Johnston
94504006780SMark Johnston if ((dtp->dt_proc_env = dt_zalloc(dtp, sizeof (char *) * i)) == NULL)
94604006780SMark Johnston return;
94704006780SMark Johnston
94804006780SMark Johnston for (i = 0, p = environ; *p != NULL; i++, p++) {
94904006780SMark Johnston if ((dtp->dt_proc_env[i] = strdup(*p)) == NULL)
95004006780SMark Johnston goto err;
9516ff6d951SJohn Birrell }
95204006780SMark Johnston for (p = envdef; *p != NULL; i++, p++) {
95304006780SMark Johnston if ((dtp->dt_proc_env[i] = strdup(*p)) == NULL)
95404006780SMark Johnston goto err;
95504006780SMark Johnston }
95604006780SMark Johnston
95704006780SMark Johnston return;
95804006780SMark Johnston
95904006780SMark Johnston err:
96004006780SMark Johnston while (--i != 0) {
96104006780SMark Johnston dt_free(dtp, dtp->dt_proc_env[i]);
96204006780SMark Johnston }
96304006780SMark Johnston dt_free(dtp, dtp->dt_proc_env);
96404006780SMark Johnston dtp->dt_proc_env = NULL;
9656ff6d951SJohn Birrell }
9666ff6d951SJohn Birrell
9676ff6d951SJohn Birrell void
dt_proc_fini(dtrace_hdl_t * dtp)96804006780SMark Johnston dt_proc_fini(dtrace_hdl_t *dtp)
9696ff6d951SJohn Birrell {
9706ff6d951SJohn Birrell dt_proc_hash_t *dph = dtp->dt_procs;
9716ff6d951SJohn Birrell dt_proc_t *dpr;
97204006780SMark Johnston char **p;
9736ff6d951SJohn Birrell
9746ff6d951SJohn Birrell while ((dpr = dt_list_next(&dph->dph_lrulist)) != NULL)
9756ff6d951SJohn Birrell dt_proc_destroy(dtp, dpr->dpr_proc);
9766ff6d951SJohn Birrell
9776ff6d951SJohn Birrell dtp->dt_procs = NULL;
9786ff6d951SJohn Birrell dt_free(dtp, dph);
97904006780SMark Johnston
98004006780SMark Johnston for (p = dtp->dt_proc_env; *p != NULL; p++)
98104006780SMark Johnston dt_free(dtp, *p);
98204006780SMark Johnston
98304006780SMark Johnston dt_free(dtp, dtp->dt_proc_env);
98404006780SMark Johnston dtp->dt_proc_env = NULL;
9856ff6d951SJohn Birrell }
9866ff6d951SJohn Birrell
9876ff6d951SJohn Birrell struct ps_prochandle *
dtrace_proc_create(dtrace_hdl_t * dtp,const char * file,char * const * argv,proc_child_func * pcf,void * child_arg)98856b35563SCraig Rodrigues dtrace_proc_create(dtrace_hdl_t *dtp, const char *file, char *const *argv,
98956b35563SCraig Rodrigues proc_child_func *pcf, void *child_arg)
9906ff6d951SJohn Birrell {
9916ff6d951SJohn Birrell dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target");
99256b35563SCraig Rodrigues struct ps_prochandle *P = dt_proc_create(dtp, file, argv, pcf, child_arg);
9936ff6d951SJohn Birrell
9940f2bd1e8SRui Paulo if (P != NULL && idp != NULL && idp->di_id == 0) {
995bbda5851SJohn Birrell idp->di_id = proc_getpid(P); /* $target = created pid */
9960f2bd1e8SRui Paulo }
9976ff6d951SJohn Birrell
9986ff6d951SJohn Birrell return (P);
9996ff6d951SJohn Birrell }
10006ff6d951SJohn Birrell
10016ff6d951SJohn Birrell struct ps_prochandle *
dtrace_proc_grab(dtrace_hdl_t * dtp,pid_t pid,int flags)10026ff6d951SJohn Birrell dtrace_proc_grab(dtrace_hdl_t *dtp, pid_t pid, int flags)
10036ff6d951SJohn Birrell {
10046ff6d951SJohn Birrell dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target");
10056ff6d951SJohn Birrell struct ps_prochandle *P = dt_proc_grab(dtp, pid, flags, 0);
10066ff6d951SJohn Birrell
10076ff6d951SJohn Birrell if (P != NULL && idp != NULL && idp->di_id == 0)
10086ff6d951SJohn Birrell idp->di_id = pid; /* $target = grabbed pid */
10096ff6d951SJohn Birrell
10106ff6d951SJohn Birrell return (P);
10116ff6d951SJohn Birrell }
10126ff6d951SJohn Birrell
10136ff6d951SJohn Birrell void
dtrace_proc_release(dtrace_hdl_t * dtp,struct ps_prochandle * P)10146ff6d951SJohn Birrell dtrace_proc_release(dtrace_hdl_t *dtp, struct ps_prochandle *P)
10156ff6d951SJohn Birrell {
10166ff6d951SJohn Birrell dt_proc_release(dtp, P);
10176ff6d951SJohn Birrell }
10186ff6d951SJohn Birrell
10196ff6d951SJohn Birrell void
dtrace_proc_continue(dtrace_hdl_t * dtp,struct ps_prochandle * P)10206ff6d951SJohn Birrell dtrace_proc_continue(dtrace_hdl_t *dtp, struct ps_prochandle *P)
10216ff6d951SJohn Birrell {
10226ff6d951SJohn Birrell dt_proc_continue(dtp, P);
10236ff6d951SJohn Birrell }
1024