dt_proc.c revision 58dbc5075c2263a035b497f4bb080ab9bfb6aab4
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess * CDDL HEADER START
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess * The contents of this file are subject to the terms of the
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess * Common Development and Distribution License (the "License").
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess * You may not use this file except in compliance with the License.
5a58787efeb02a1c3f06569d019ad81fd2efa06end * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
5a58787efeb02a1c3f06569d019ad81fd2efa06end * See the License for the specific language governing permissions
5a58787efeb02a1c3f06569d019ad81fd2efa06end * and limitations under the License.
5a58787efeb02a1c3f06569d019ad81fd2efa06end * When distributing Covered Code, include this CDDL HEADER in each
5a58787efeb02a1c3f06569d019ad81fd2efa06end * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
3f08db06526d6901aa08c110b5bc7dde6bc39905nd * If applicable, add the following below this CDDL HEADER, with the
5a58787efeb02a1c3f06569d019ad81fd2efa06end * fields enclosed by brackets "[]" replaced with your own identifying
5a58787efeb02a1c3f06569d019ad81fd2efa06end * information: Portions Copyright [yyyy] [name of copyright owner]
3f08db06526d6901aa08c110b5bc7dde6bc39905nd * CDDL HEADER END
4b3a8afbfcea8b265d179a122bf40dfedd1ce280takashi * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung * Use is subject to license terms.
15107611640cec4e666dd7e2e1dee15c270e9e98rbowen * DTrace Process Control
15107611640cec4e666dd7e2e1dee15c270e9e98rbowen * This file provides a set of routines that permit libdtrace and its clients
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess * to create and grab process handles using libproc, and to share these handles
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * between library mechanisms that need libproc access, such as ustack(), and
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * client mechanisms that need libproc access, such as dtrace(1M) -c and -p.
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * The library provides several mechanisms in the libproc control layer:
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * Reference Counting: The library code and client code can independently grab
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * the same process handles without interfering with one another. Only when
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * the reference count drops to zero and the handle is not being cached (see
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * below for more information on caching) will Prelease() be called on it.
5a58787efeb02a1c3f06569d019ad81fd2efa06end * Handle Caching: If a handle is grabbed PGRAB_RDONLY (e.g. by ustack()) and
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * the reference count drops to zero, the handle is not immediately released.
5a58787efeb02a1c3f06569d019ad81fd2efa06end * Instead, libproc handles are maintained on dph_lrulist in order from most-
5a58787efeb02a1c3f06569d019ad81fd2efa06end * recently accessed to least-recently accessed. Idle handles are maintained
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * until a pre-defined LRU cache limit is exceeded, permitting repeated calls
5a58787efeb02a1c3f06569d019ad81fd2efa06end * to ustack() to avoid the overhead of releasing and re-grabbing processes.
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * Process Control: For processes that are grabbed for control (~PGRAB_RDONLY)
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess * or created by dt_proc_create(), a control thread is created to provide
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * callbacks on process exit and symbol table caching on dlopen()s.
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * MT-Safety: Libproc is not MT-Safe, so dt_proc_lock() and dt_proc_unlock()
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * are provided to synchronize access to the libproc handle between libdtrace
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * code and client code and the control thread's use of the ps_prochandle.
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess * NOTE: MT-Safety is NOT provided for libdtrace itself, or for use of the
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess * dtrace_proc_grab/dtrace_proc_create mechanisms. Like all exported libdtrace
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess * calls, these are assumed to be MT-Unsafe. MT-Safety is ONLY provided for
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * synchronization between libdtrace control threads and the client thread.
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * The ps_prochandles themselves are maintained along with a dt_proc_t struct
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * in a hash table indexed by PID. This provides basic locking and reference
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * counting. The dt_proc_t is also maintained in LRU order on dph_lrulist.
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * The dph_lrucnt and dph_lrulim count the number of cacheable processes and
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * the current limit on the number of actively cached entries.
6e14faf37935e36804b8bad802bc9dd58f3cf65dsf * The control thread for a process establishes breakpoints at the rtld_db
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * locations of interest, updates mappings and symbol tables at these points,
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * and handles exec and fork (by always following the parent). The control
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf * thread automatically exits when the process dies or control is lost.
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * A simple notification mechanism is provided for libdtrace clients using
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * dtrace_handle_proc() for notification of PS_UNDEAD or PS_LOST events. If
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * such an event occurs, the dt_proc_t itself is enqueued on a notification
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * list and the control thread broadcasts to dph_cv. dtrace_sleep() will wake
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * up using this condition and will then call the client handler as necessary.
6e14faf37935e36804b8bad802bc9dd58f3cf65dsf#define IS_SYS_FORK(w) (w == SYS_vfork || w == SYS_fork1 || \
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsfdt_proc_bpcreate(dt_proc_t *dpr, uintptr_t addr, dt_bkpt_f *func, void *data)
60a4b2c422dcbb08a554fb193105c08da592718bpoirier if ((dbp = dt_zalloc(dpr->dpr_hdl, sizeof (dt_bkpt_t))) != NULL) {
60a4b2c422dcbb08a554fb193105c08da592718bpoirier if (Psetbkpt(P, dbp->dbp_addr, &dbp->dbp_instr) == 0)
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kessstatic void
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess for (dbp = dt_list_next(&dpr->dpr_bps); dbp != NULL; dbp = nbp) {
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess const lwpstatus_t *psp = &Pstatus(dpr->dpr_proc)->pr_lwp;
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess dt_dprintf("pid %d: spurious breakpoint wakeup for %lx\n",
5a58787efeb02a1c3f06569d019ad81fd2efa06end (int)dpr->dpr_pid, (ulong_t)dbp->dbp_addr, ++dbp->dbp_hits);
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kessstatic void
60a4b2c422dcbb08a554fb193105c08da592718bpoirierdt_proc_notify(dtrace_hdl_t *dtp, dt_proc_hash_t *dph, dt_proc_t *dpr,
60a4b2c422dcbb08a554fb193105c08da592718bpoirier const char *msg)
60a4b2c422dcbb08a554fb193105c08da592718bpoirier dt_proc_notify_t *dprn = dt_alloc(dtp, sizeof (dt_proc_notify_t));
60a4b2c422dcbb08a554fb193105c08da592718bpoirier dt_dprintf("failed to allocate notification for %d %s\n",
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess * Check to see if the control thread was requested to stop when the victim
60a4b2c422dcbb08a554fb193105c08da592718bpoirier * process reached a particular event (why) rather than continuing the victim.
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess * If 'why' is set in the stop mask, we wait on dpr_cv for dt_proc_continue().
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess * If 'why' is not set, this function returns immediately and does nothing.
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kessstatic void
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess * We disable breakpoints while stopped to preserve the
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess * integrity of the program text for both our own disassembly
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess * and that of the kernel.
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess/*ARGSUSED*/
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kessstatic void
6e14faf37935e36804b8bad802bc9dd58f3cf65dsfdt_proc_bpmain(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *fname)
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess dt_dprintf("pid %d: breakpoint at %s()\n", (int)dpr->dpr_pid, fname);
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kessdt_proc_rdevent(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *evname)
6e14faf37935e36804b8bad802bc9dd58f3cf65dsf if ((err = rd_event_getmsg(dpr->dpr_rtld, &rdm)) != RD_OK) {
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess dt_dprintf("pid %d: failed to get %s event message: %s\n",
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kessstatic void
60a4b2c422dcbb08a554fb193105c08da592718bpoirierdt_proc_rdwatch(dt_proc_t *dpr, rd_event_e event, const char *evname)
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess if ((err = rd_event_addr(dpr->dpr_rtld, event, &rdn)) != RD_OK) {
fefb8b844b6286bfc41bb2e0c4cc003b8e7d4ff2kess dt_dprintf("pid %d: failed to get event address for %s: %s\n",
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung dt_dprintf("pid %d: event %s has unexpected type %d\n",
if (exec) {
* PR_REQUESTED stop. Since PCWSTOP/Pstopstatus() can be applied repeatedly
Psync(P);
Psync(P);
typedef struct dt_proc_control_data {
switch (Pstate(P)) {
case PS_STOP:
case PS_LOST:
if (Preopen(P) == 0)
goto pwait_locked;
case PS_UNDEAD:
if (notify)
return (NULL);
static struct ps_prochandle *
return (NULL);
if (remove)
return (dpr);
int rflag;
int err;
(void) pthread_attr_init(&a);
if (err == 0) {
(void) pthread_attr_destroy(&a);
return (err);
struct ps_prochandle *
int err;
struct ps_prochandle *
int err;
struct ps_prochandle *
struct ps_prochandle *