10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*2235Skk112340 * Common Development and Distribution License (the "License"). 6*2235Skk112340 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*2235Skk112340 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * This file contains a set of generic routines for periodically 300Sstevel@tonic-gate * sampling the state of another process, or tree of processes. 310Sstevel@tonic-gate * 320Sstevel@tonic-gate * It is built upon the infrastructure provided by libproc. 330Sstevel@tonic-gate */ 340Sstevel@tonic-gate 350Sstevel@tonic-gate #include <sys/wait.h> 360Sstevel@tonic-gate #include <sys/syscall.h> 370Sstevel@tonic-gate #include <sys/time.h> 380Sstevel@tonic-gate #include <libproc.h> 390Sstevel@tonic-gate #include <stdio.h> 400Sstevel@tonic-gate #include <stdlib.h> 410Sstevel@tonic-gate #include <errno.h> 420Sstevel@tonic-gate #include <unistd.h> 430Sstevel@tonic-gate #include <signal.h> 440Sstevel@tonic-gate #include <string.h> 450Sstevel@tonic-gate #include <strings.h> 460Sstevel@tonic-gate #include <limits.h> 470Sstevel@tonic-gate #include <ctype.h> 480Sstevel@tonic-gate #include <libintl.h> 490Sstevel@tonic-gate #include <libcpc.h> 500Sstevel@tonic-gate #include <sys/cpc_impl.h> 510Sstevel@tonic-gate 520Sstevel@tonic-gate #include "libpctx.h" 530Sstevel@tonic-gate 540Sstevel@tonic-gate struct __pctx { 550Sstevel@tonic-gate pctx_errfn_t *errfn; 560Sstevel@tonic-gate struct ps_prochandle *Pr; 570Sstevel@tonic-gate void *uarg; 580Sstevel@tonic-gate pctx_sysc_execfn_t *exec; 590Sstevel@tonic-gate pctx_sysc_forkfn_t *fork; 600Sstevel@tonic-gate pctx_sysc_exitfn_t *exit; 610Sstevel@tonic-gate pctx_sysc_lwp_createfn_t *lwp_create; 620Sstevel@tonic-gate pctx_init_lwpfn_t *init_lwp; 630Sstevel@tonic-gate pctx_fini_lwpfn_t *fini_lwp; 640Sstevel@tonic-gate pctx_sysc_lwp_exitfn_t *lwp_exit; 650Sstevel@tonic-gate int verbose; 660Sstevel@tonic-gate int created; 670Sstevel@tonic-gate int sigblocked; 680Sstevel@tonic-gate sigset_t savedset; 690Sstevel@tonic-gate cpc_t *cpc; 700Sstevel@tonic-gate }; 710Sstevel@tonic-gate 720Sstevel@tonic-gate static void (*pctx_cpc_callback)(cpc_t *cpc, struct __pctx *pctx); 730Sstevel@tonic-gate 740Sstevel@tonic-gate static void 750Sstevel@tonic-gate pctx_default_errfn(const char *fn, const char *fmt, va_list ap) 760Sstevel@tonic-gate { 770Sstevel@tonic-gate (void) fprintf(stderr, "libpctx: pctx_%s: ", fn); 780Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap); 790Sstevel@tonic-gate } 800Sstevel@tonic-gate 810Sstevel@tonic-gate /*PRINTFLIKE3*/ 820Sstevel@tonic-gate static void 830Sstevel@tonic-gate pctx_error(pctx_t *pctx, const char *fn, const char *fmt, ...) 840Sstevel@tonic-gate { 850Sstevel@tonic-gate va_list ap; 860Sstevel@tonic-gate 870Sstevel@tonic-gate va_start(ap, fmt); 880Sstevel@tonic-gate pctx->errfn(fn, fmt, ap); 890Sstevel@tonic-gate va_end(ap); 900Sstevel@tonic-gate } 910Sstevel@tonic-gate 920Sstevel@tonic-gate /* 930Sstevel@tonic-gate * Create a new process and bind the user args for it 940Sstevel@tonic-gate */ 950Sstevel@tonic-gate pctx_t * 960Sstevel@tonic-gate pctx_create( 970Sstevel@tonic-gate const char *filename, 980Sstevel@tonic-gate char *const *argv, 990Sstevel@tonic-gate void *arg, 1000Sstevel@tonic-gate int verbose, 1010Sstevel@tonic-gate pctx_errfn_t *errfn) 1020Sstevel@tonic-gate { 1030Sstevel@tonic-gate static const char fn[] = "create"; 1040Sstevel@tonic-gate int err; 1050Sstevel@tonic-gate pctx_t *pctx; 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate pctx = calloc(1, sizeof (*pctx)); 1080Sstevel@tonic-gate pctx->uarg = arg; 1090Sstevel@tonic-gate pctx->verbose = verbose; 1100Sstevel@tonic-gate pctx->errfn = errfn ? errfn : pctx_default_errfn; 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate if ((pctx->Pr = Pcreate(filename, argv, &err, 0, 0)) == NULL) { 1130Sstevel@tonic-gate switch (err) { 1140Sstevel@tonic-gate case C_PERM: 1150Sstevel@tonic-gate pctx_error(pctx, fn, gettext("cannot trace set-id or " 1160Sstevel@tonic-gate "unreadable program '%s'\n"), filename); 1170Sstevel@tonic-gate break; 1180Sstevel@tonic-gate case C_LP64: 1190Sstevel@tonic-gate pctx_error(pctx, fn, gettext("cannot control LP64 " 1200Sstevel@tonic-gate "program '%s'\n"), filename); 1210Sstevel@tonic-gate break; 1220Sstevel@tonic-gate case C_NOEXEC: 1230Sstevel@tonic-gate pctx_error(pctx, fn, gettext("cannot execute " 1240Sstevel@tonic-gate "program '%s'\n"), filename); 1250Sstevel@tonic-gate break; 1260Sstevel@tonic-gate case C_NOENT: 1270Sstevel@tonic-gate pctx_error(pctx, fn, gettext("cannot find" 1280Sstevel@tonic-gate "program '%s'\n"), filename); 1290Sstevel@tonic-gate break; 1300Sstevel@tonic-gate case C_FORK: 1310Sstevel@tonic-gate pctx_error(pctx, fn, gettext("cannot fork, " 1320Sstevel@tonic-gate "program '%s'\n"), filename); 1330Sstevel@tonic-gate break; 1340Sstevel@tonic-gate default: 1350Sstevel@tonic-gate pctx_error(pctx, fn, gettext("%s, program '%s'\n"), 1360Sstevel@tonic-gate Pcreate_error(err), filename); 1370Sstevel@tonic-gate break; 1380Sstevel@tonic-gate } 1390Sstevel@tonic-gate free(pctx); 1400Sstevel@tonic-gate return (NULL); 1410Sstevel@tonic-gate } 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate if (Psysentry(pctx->Pr, SYS_exit, 1) == -1) { 1440Sstevel@tonic-gate pctx_error(pctx, fn, 1450Sstevel@tonic-gate gettext("can't stop-on-exit() program '%s'\n"), filename); 1460Sstevel@tonic-gate Prelease(pctx->Pr, PRELEASE_KILL); 1470Sstevel@tonic-gate free(pctx); 1480Sstevel@tonic-gate return (NULL); 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate /* 1510Sstevel@tonic-gate * Set kill-on-last-close so the controlled process 1520Sstevel@tonic-gate * dies if we die. 1530Sstevel@tonic-gate */ 1540Sstevel@tonic-gate pctx->created = 1; 1550Sstevel@tonic-gate (void) Psetflags(pctx->Pr, PR_KLC); 1560Sstevel@tonic-gate (void) pctx_set_events(pctx, PCTX_NULL_EVENT); 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate return (pctx); 1590Sstevel@tonic-gate } 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate /* 1620Sstevel@tonic-gate * Capture an existing process and bind the user args for it 1630Sstevel@tonic-gate */ 1640Sstevel@tonic-gate pctx_t * 1650Sstevel@tonic-gate pctx_capture(pid_t pid, void *arg, int verbose, pctx_errfn_t *errfn) 1660Sstevel@tonic-gate { 1670Sstevel@tonic-gate static const char fn[] = "capture"; 1680Sstevel@tonic-gate int err; 1690Sstevel@tonic-gate pctx_t *pctx; 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate pctx = calloc(1, sizeof (*pctx)); 1720Sstevel@tonic-gate pctx->uarg = arg; 1730Sstevel@tonic-gate pctx->verbose = verbose; 1740Sstevel@tonic-gate pctx->errfn = errfn ? errfn : pctx_default_errfn; 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate if ((pctx->Pr = Pgrab(pid, 0, &err)) == NULL) { 1770Sstevel@tonic-gate switch (err) { 1780Sstevel@tonic-gate case G_NOPROC: 1790Sstevel@tonic-gate pctx_error(pctx, fn, 1800Sstevel@tonic-gate gettext("pid %d doesn't exist\n"), (int)pid); 1810Sstevel@tonic-gate break; 1820Sstevel@tonic-gate case G_ZOMB: 1830Sstevel@tonic-gate pctx_error(pctx, fn, 1840Sstevel@tonic-gate gettext("pid %d is a zombie\n"), (int)pid); 1850Sstevel@tonic-gate break; 1860Sstevel@tonic-gate case G_PERM: 1870Sstevel@tonic-gate pctx_error(pctx, fn, 1880Sstevel@tonic-gate gettext("pid %d: permission denied\n"), (int)pid); 1890Sstevel@tonic-gate break; 1900Sstevel@tonic-gate case G_BUSY: 1910Sstevel@tonic-gate pctx_error(pctx, fn, 1920Sstevel@tonic-gate gettext("pid %d is already being traced\n"), 1930Sstevel@tonic-gate (int)pid); 1940Sstevel@tonic-gate break; 1950Sstevel@tonic-gate case G_SYS: 1960Sstevel@tonic-gate pctx_error(pctx, fn, 1970Sstevel@tonic-gate gettext("pid %d is a system process\n"), (int)pid); 1980Sstevel@tonic-gate break; 1990Sstevel@tonic-gate case G_SELF: 2000Sstevel@tonic-gate pctx_error(pctx, fn, 2010Sstevel@tonic-gate gettext("cannot capture self!\n")); 2020Sstevel@tonic-gate break; 2030Sstevel@tonic-gate case G_LP64: 2040Sstevel@tonic-gate pctx_error(pctx, fn, gettext("cannot control LP64 " 2050Sstevel@tonic-gate "process, pid %d\n"), (int)pid); 2060Sstevel@tonic-gate break; 2070Sstevel@tonic-gate default: 2080Sstevel@tonic-gate pctx_error(pctx, fn, gettext("%s: pid %d\n"), 2090Sstevel@tonic-gate Pgrab_error(err), (int)pid); 2100Sstevel@tonic-gate break; 2110Sstevel@tonic-gate } 2120Sstevel@tonic-gate free(pctx); 2130Sstevel@tonic-gate return (NULL); 2140Sstevel@tonic-gate } 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate if (Psysentry(pctx->Pr, SYS_exit, 1) == -1) { 2170Sstevel@tonic-gate pctx_error(pctx, fn, 2180Sstevel@tonic-gate gettext("can't stop-on-exit() pid %d\n"), (int)pid); 2190Sstevel@tonic-gate Prelease(pctx->Pr, PRELEASE_CLEAR); 2200Sstevel@tonic-gate free(pctx); 2210Sstevel@tonic-gate return (NULL); 2220Sstevel@tonic-gate } 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate /* 2250Sstevel@tonic-gate * Set run-on-last-close so the controlled process 2260Sstevel@tonic-gate * runs even if we die on a signal. This is because 2270Sstevel@tonic-gate * we grabbed an existing process - it would be impolite 2280Sstevel@tonic-gate * to cause it to die if we exit prematurely. 2290Sstevel@tonic-gate */ 2300Sstevel@tonic-gate pctx->created = 0; 2310Sstevel@tonic-gate (void) Psetflags(pctx->Pr, PR_RLC); 2320Sstevel@tonic-gate (void) pctx_set_events(pctx, PCTX_NULL_EVENT); 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate return (pctx); 2350Sstevel@tonic-gate } 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate /*ARGSUSED*/ 2380Sstevel@tonic-gate static void 2390Sstevel@tonic-gate default_void(pctx_t *pctx) 2400Sstevel@tonic-gate {} 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate /*ARGSUSED*/ 2430Sstevel@tonic-gate static int 2440Sstevel@tonic-gate default_int(pctx_t *pctx) 2450Sstevel@tonic-gate { 2460Sstevel@tonic-gate return (0); 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate int 2500Sstevel@tonic-gate pctx_set_events(pctx_t *pctx, ...) 2510Sstevel@tonic-gate { 2520Sstevel@tonic-gate static const char fn[] = "set_events"; 2530Sstevel@tonic-gate va_list pvar; 2540Sstevel@tonic-gate int error = 0; 2550Sstevel@tonic-gate pctx_event_t event; 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate va_start(pvar, pctx); 2580Sstevel@tonic-gate do { 2590Sstevel@tonic-gate switch (event = (pctx_event_t)va_arg(pvar, pctx_event_t)) { 2600Sstevel@tonic-gate case PCTX_NULL_EVENT: 2610Sstevel@tonic-gate break; 2620Sstevel@tonic-gate case PCTX_SYSC_EXEC_EVENT: 2630Sstevel@tonic-gate pctx->exec = (pctx_sysc_execfn_t *) 2640Sstevel@tonic-gate va_arg(pvar, pctx_sysc_execfn_t *); 2650Sstevel@tonic-gate break; 2660Sstevel@tonic-gate case PCTX_SYSC_FORK_EVENT: 2670Sstevel@tonic-gate pctx->fork = (pctx_sysc_forkfn_t *) 2680Sstevel@tonic-gate va_arg(pvar, pctx_sysc_forkfn_t *); 2690Sstevel@tonic-gate break; 2700Sstevel@tonic-gate case PCTX_SYSC_EXIT_EVENT: /* always intercepted */ 2710Sstevel@tonic-gate pctx->exit = (pctx_sysc_exitfn_t *) 2720Sstevel@tonic-gate va_arg(pvar, pctx_sysc_exitfn_t *); 2730Sstevel@tonic-gate break; 2740Sstevel@tonic-gate case PCTX_SYSC_LWP_CREATE_EVENT: 2750Sstevel@tonic-gate pctx->lwp_create = (pctx_sysc_lwp_createfn_t *) 2760Sstevel@tonic-gate va_arg(pvar, pctx_sysc_lwp_createfn_t *); 2770Sstevel@tonic-gate break; 2780Sstevel@tonic-gate case PCTX_INIT_LWP_EVENT: 2790Sstevel@tonic-gate pctx->init_lwp = (pctx_init_lwpfn_t *) 2800Sstevel@tonic-gate va_arg(pvar, pctx_init_lwpfn_t *); 2810Sstevel@tonic-gate break; 2820Sstevel@tonic-gate case PCTX_FINI_LWP_EVENT: 2830Sstevel@tonic-gate pctx->fini_lwp = (pctx_fini_lwpfn_t *) 2840Sstevel@tonic-gate va_arg(pvar, pctx_fini_lwpfn_t *); 2850Sstevel@tonic-gate break; 2860Sstevel@tonic-gate case PCTX_SYSC_LWP_EXIT_EVENT: 2870Sstevel@tonic-gate pctx->lwp_exit = (pctx_sysc_lwp_exitfn_t *) 2880Sstevel@tonic-gate va_arg(pvar, pctx_sysc_lwp_exitfn_t *); 2890Sstevel@tonic-gate break; 2900Sstevel@tonic-gate default: 2910Sstevel@tonic-gate pctx_error(pctx, fn, 2920Sstevel@tonic-gate gettext("unknown event type %x\n"), event); 2930Sstevel@tonic-gate error = -1; 2940Sstevel@tonic-gate break; 2950Sstevel@tonic-gate } 2960Sstevel@tonic-gate } while (event != PCTX_NULL_EVENT && error == 0); 2970Sstevel@tonic-gate va_end(pvar); 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate if (error != 0) 3000Sstevel@tonic-gate return (error); 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate if (pctx->exec == NULL) 3030Sstevel@tonic-gate pctx->exec = (pctx_sysc_execfn_t *)default_int; 3040Sstevel@tonic-gate if (pctx->fork == NULL) 3050Sstevel@tonic-gate pctx->fork = (pctx_sysc_forkfn_t *)default_void; 3060Sstevel@tonic-gate if (pctx->exit == NULL) 3070Sstevel@tonic-gate pctx->exit = (pctx_sysc_exitfn_t *)default_void; 3080Sstevel@tonic-gate if (pctx->lwp_create == NULL) 3090Sstevel@tonic-gate pctx->lwp_create = (pctx_sysc_lwp_createfn_t *)default_int; 3100Sstevel@tonic-gate if (pctx->init_lwp == NULL) 3110Sstevel@tonic-gate pctx->init_lwp = (pctx_init_lwpfn_t *)default_int; 3120Sstevel@tonic-gate if (pctx->fini_lwp == NULL) 3130Sstevel@tonic-gate pctx->fini_lwp = (pctx_fini_lwpfn_t *)default_int; 3140Sstevel@tonic-gate if (pctx->lwp_exit == NULL) 3150Sstevel@tonic-gate pctx->lwp_exit = (pctx_sysc_lwp_exitfn_t *)default_int; 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate if (pctx->fork != (pctx_sysc_forkfn_t *)default_void) { 3180Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_forkall, 1); 3190Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_vfork, 1); 3200Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_fork1, 1); 3210Sstevel@tonic-gate if (Psetflags(pctx->Pr, PR_FORK) == -1) 3220Sstevel@tonic-gate error = -1; 3230Sstevel@tonic-gate } else { 3240Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_forkall, 0); 3250Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_vfork, 0); 3260Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_fork1, 0); 3270Sstevel@tonic-gate if (Punsetflags(pctx->Pr, PR_FORK) == -1) 3280Sstevel@tonic-gate error = -1; 3290Sstevel@tonic-gate } 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate /* 3320Sstevel@tonic-gate * exec causes termination of all but the exec-ing lwp, 3330Sstevel@tonic-gate * and resets the lwpid to one in the new address space. 3340Sstevel@tonic-gate */ 3350Sstevel@tonic-gate if (pctx->exec != (pctx_sysc_execfn_t *)default_int || 3360Sstevel@tonic-gate pctx->fini_lwp != (pctx_fini_lwpfn_t *)default_int || 3370Sstevel@tonic-gate pctx->init_lwp != (pctx_init_lwpfn_t *)default_int) { 3380Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_exec, 1); 3390Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_execve, 1); 3400Sstevel@tonic-gate (void) Psysentry(pctx->Pr, SYS_exec, 1); 3410Sstevel@tonic-gate (void) Psysentry(pctx->Pr, SYS_execve, 1); 3420Sstevel@tonic-gate } else { 3430Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_exec, 0); 3440Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_execve, 0); 3450Sstevel@tonic-gate (void) Psysentry(pctx->Pr, SYS_exec, 0); 3460Sstevel@tonic-gate (void) Psysentry(pctx->Pr, SYS_execve, 0); 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_lwp_create, 3500Sstevel@tonic-gate pctx->lwp_create != (pctx_sysc_lwp_createfn_t *)default_int || 3510Sstevel@tonic-gate pctx->init_lwp != (pctx_init_lwpfn_t *)default_int); 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate (void) Psysentry(pctx->Pr, SYS_lwp_exit, 3540Sstevel@tonic-gate pctx->lwp_exit != (pctx_sysc_lwp_exitfn_t *)default_int || 3550Sstevel@tonic-gate pctx->fini_lwp != (pctx_fini_lwpfn_t *)default_int); 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate return (0); 3580Sstevel@tonic-gate } 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate static sigset_t termsig; 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate static void 3630Sstevel@tonic-gate __libpctx_init(void) 3640Sstevel@tonic-gate { 3650Sstevel@tonic-gate /* 3660Sstevel@tonic-gate * Initialize the signal set used to shield ourselves from 3670Sstevel@tonic-gate * death-by-terminal-signal while the agent lwp is running. 3680Sstevel@tonic-gate */ 3690Sstevel@tonic-gate (void) sigemptyset(&termsig); 3700Sstevel@tonic-gate (void) sigaddset(&termsig, SIGHUP); 3710Sstevel@tonic-gate (void) sigaddset(&termsig, SIGTERM); 3720Sstevel@tonic-gate (void) sigaddset(&termsig, SIGINT); 3730Sstevel@tonic-gate (void) sigaddset(&termsig, SIGQUIT); 3740Sstevel@tonic-gate } 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate #pragma init(__libpctx_init) 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate static void 3790Sstevel@tonic-gate pctx_begin_syscalls(pctx_t *pctx) 3800Sstevel@tonic-gate { 3810Sstevel@tonic-gate if (pctx->Pr == NULL) 3820Sstevel@tonic-gate return; 3830Sstevel@tonic-gate if (pctx->sigblocked++ == 0) { 3840Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &termsig, &pctx->savedset); 3850Sstevel@tonic-gate (void) Pcreate_agent(pctx->Pr); 3860Sstevel@tonic-gate } 3870Sstevel@tonic-gate } 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate static void 3900Sstevel@tonic-gate pctx_end_syscalls(pctx_t *pctx) 3910Sstevel@tonic-gate { 3920Sstevel@tonic-gate if (pctx->Pr == NULL) 3930Sstevel@tonic-gate return; 3940Sstevel@tonic-gate if (--pctx->sigblocked == 0) { 3950Sstevel@tonic-gate (void) Pdestroy_agent(pctx->Pr); 3960Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &pctx->savedset, NULL); 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate } 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate /* 4010Sstevel@tonic-gate * Iterate over the valid lwpids in the process, invoking the 4020Sstevel@tonic-gate * action function on each one. 4030Sstevel@tonic-gate */ 4040Sstevel@tonic-gate static int 4050Sstevel@tonic-gate pctx_lwpiterate(pctx_t *pctx, int (*action)(pctx_t *, pid_t, id_t, void *)) 4060Sstevel@tonic-gate { 4070Sstevel@tonic-gate const pstatus_t *pstatus; 4080Sstevel@tonic-gate char lstatus[64]; 4090Sstevel@tonic-gate struct stat statb; 4100Sstevel@tonic-gate lwpstatus_t *lwps; 4110Sstevel@tonic-gate prheader_t *prh; 4120Sstevel@tonic-gate int fd, nlwp; 4130Sstevel@tonic-gate int ret = 0; 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate if (action == (int (*)(pctx_t *, pid_t, id_t, void *))default_int) 4160Sstevel@tonic-gate return (0); 4170Sstevel@tonic-gate 4180Sstevel@tonic-gate pstatus = Pstatus(pctx->Pr); 4190Sstevel@tonic-gate if (pstatus->pr_nlwp <= 1) { 4200Sstevel@tonic-gate pctx_begin_syscalls(pctx); 4210Sstevel@tonic-gate ret = action(pctx, pstatus->pr_pid, 1, pctx->uarg); 4220Sstevel@tonic-gate pctx_end_syscalls(pctx); 4230Sstevel@tonic-gate return (ret); 4240Sstevel@tonic-gate } 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate (void) snprintf(lstatus, sizeof (lstatus), 4270Sstevel@tonic-gate "/proc/%d/lstatus", (int)pstatus->pr_pid); 4280Sstevel@tonic-gate 4290Sstevel@tonic-gate if ((fd = open(lstatus, O_RDONLY)) < 0 || 4300Sstevel@tonic-gate fstat(fd, &statb) != 0) { 4310Sstevel@tonic-gate if (fd >= 0) 4320Sstevel@tonic-gate (void) close(fd); 4330Sstevel@tonic-gate return (-1); 4340Sstevel@tonic-gate } 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate prh = malloc(statb.st_size); 4370Sstevel@tonic-gate if (read(fd, prh, statb.st_size) < 4380Sstevel@tonic-gate sizeof (prheader_t) + sizeof (lwpstatus_t)) { 4390Sstevel@tonic-gate (void) close(fd); 4400Sstevel@tonic-gate free(prh); 4410Sstevel@tonic-gate return (-1); 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate (void) close(fd); 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate /* LINTED pointer cast may result in improper alignment */ 4460Sstevel@tonic-gate lwps = (lwpstatus_t *)(prh + 1); 4470Sstevel@tonic-gate pctx_begin_syscalls(pctx); 4480Sstevel@tonic-gate for (nlwp = prh->pr_nent; nlwp > 0; nlwp--) { 4490Sstevel@tonic-gate if (action(pctx, 4500Sstevel@tonic-gate pstatus->pr_pid, lwps->pr_lwpid, pctx->uarg) != 0) 4510Sstevel@tonic-gate ret = -1; 4520Sstevel@tonic-gate /* LINTED pointer cast may result in improper alignment */ 4530Sstevel@tonic-gate lwps = (lwpstatus_t *)((char *)lwps + prh->pr_entsize); 4540Sstevel@tonic-gate } 4550Sstevel@tonic-gate pctx_end_syscalls(pctx); 4560Sstevel@tonic-gate free(prh); 4570Sstevel@tonic-gate return (ret); 4580Sstevel@tonic-gate } 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate /* 4610Sstevel@tonic-gate * Free any associated state, but leave the process stopped if it 4620Sstevel@tonic-gate * is still under our control. (If it isn't under our control, 4630Sstevel@tonic-gate * it should just run to completion when we do our last close) 4640Sstevel@tonic-gate */ 4650Sstevel@tonic-gate static void 4660Sstevel@tonic-gate pctx_free(pctx_t *pctx) 4670Sstevel@tonic-gate { 4680Sstevel@tonic-gate if (pctx->cpc != NULL && pctx_cpc_callback != NULL) 4690Sstevel@tonic-gate (*pctx_cpc_callback)(pctx->cpc, pctx); 4700Sstevel@tonic-gate if (pctx->Pr) { 4710Sstevel@tonic-gate Pfree(pctx->Pr); 4720Sstevel@tonic-gate pctx->Pr = NULL; 4730Sstevel@tonic-gate } 4740Sstevel@tonic-gate pctx->errfn = pctx_default_errfn; 4750Sstevel@tonic-gate } 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate /* 4780Sstevel@tonic-gate * Completely release the process from our control and discard all our state 4790Sstevel@tonic-gate */ 4800Sstevel@tonic-gate void 4810Sstevel@tonic-gate pctx_release(pctx_t *pctx) 4820Sstevel@tonic-gate { 4830Sstevel@tonic-gate if (pctx->Pr) { 4840Sstevel@tonic-gate Prelease(pctx->Pr, PRELEASE_CLEAR); 4850Sstevel@tonic-gate pctx->Pr = NULL; 4860Sstevel@tonic-gate } 4870Sstevel@tonic-gate pctx_free(pctx); 4880Sstevel@tonic-gate bzero(pctx, sizeof (*pctx)); 4890Sstevel@tonic-gate free(pctx); 4900Sstevel@tonic-gate } 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate static void 4930Sstevel@tonic-gate msincr(struct timeval *tv, uint_t msec) 4940Sstevel@tonic-gate { 4950Sstevel@tonic-gate tv->tv_sec += msec / MILLISEC; 4960Sstevel@tonic-gate tv->tv_usec += (msec % MILLISEC) * MILLISEC; 4970Sstevel@tonic-gate if (tv->tv_usec > MICROSEC) { 4980Sstevel@tonic-gate tv->tv_sec++; 4990Sstevel@tonic-gate tv->tv_usec -= MICROSEC; 5000Sstevel@tonic-gate } 5010Sstevel@tonic-gate } 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate static uint_t 5040Sstevel@tonic-gate msdiff(struct timeval *tva, struct timeval *tvb) 5050Sstevel@tonic-gate { 5060Sstevel@tonic-gate time_t sdiff = tva->tv_sec - tvb->tv_sec; 5070Sstevel@tonic-gate suseconds_t udiff = tva->tv_usec - tvb->tv_usec; 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate if (sdiff < 0) 5100Sstevel@tonic-gate return (0); 5110Sstevel@tonic-gate if (udiff < 0) { 5120Sstevel@tonic-gate udiff += MICROSEC; 5130Sstevel@tonic-gate sdiff--; 5140Sstevel@tonic-gate } 5150Sstevel@tonic-gate if (sdiff < 0) 5160Sstevel@tonic-gate return (0); 5170Sstevel@tonic-gate if (sdiff >= (INT_MAX / MILLISEC)) 5180Sstevel@tonic-gate return ((uint_t)INT_MAX); 5190Sstevel@tonic-gate return ((uint_t)(sdiff * MILLISEC + udiff / MILLISEC)); 5200Sstevel@tonic-gate } 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate int 5230Sstevel@tonic-gate pctx_run( 5240Sstevel@tonic-gate pctx_t *pctx, 5250Sstevel@tonic-gate uint_t msec, 5260Sstevel@tonic-gate uint_t nsamples, 5270Sstevel@tonic-gate int (*tick)(pctx_t *, pid_t, id_t, void *)) 5280Sstevel@tonic-gate { 5290Sstevel@tonic-gate static const char fn[] = "run"; 5300Sstevel@tonic-gate struct timeval tvgoal, tvnow; 5310Sstevel@tonic-gate uint_t mswait = 0; 5320Sstevel@tonic-gate int running = 1; 5330Sstevel@tonic-gate const pstatus_t *pstatus; 5340Sstevel@tonic-gate psinfo_t psinfo; 5350Sstevel@tonic-gate void (*sigsaved)(); 5360Sstevel@tonic-gate id_t lwpid; 5370Sstevel@tonic-gate pid_t pid = Pstatus(pctx->Pr)->pr_pid; 5380Sstevel@tonic-gate int pstate; 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate if (msec == 0) 5410Sstevel@tonic-gate nsamples = 0; 5420Sstevel@tonic-gate if (nsamples == 0) 5430Sstevel@tonic-gate nsamples = UINT_MAX; 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate /* 5460Sstevel@tonic-gate * Casually discard any knowledge of the children we create 5470Sstevel@tonic-gate */ 5480Sstevel@tonic-gate sigsaved = signal(SIGCHLD, SIG_IGN); 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate /* 5510Sstevel@tonic-gate * Since we've just "discovered" this process which might have 5520Sstevel@tonic-gate * been running for weeks, deliver some init_lwp events so 5530Sstevel@tonic-gate * that our caller gets a handle on the process. 5540Sstevel@tonic-gate */ 5550Sstevel@tonic-gate if (pctx_lwpiterate(pctx, pctx->init_lwp) != 0) { 5560Sstevel@tonic-gate if (pctx->verbose) 5570Sstevel@tonic-gate pctx_error(pctx, fn, 5580Sstevel@tonic-gate gettext("%d: lwp discovery failed\n"), (int)pid); 5590Sstevel@tonic-gate goto bailout; 5600Sstevel@tonic-gate } 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate if (msec != 0) { 5630Sstevel@tonic-gate /* 5640Sstevel@tonic-gate * tvgoal represents the time at which the sample 5650Sstevel@tonic-gate * should next be taken. 5660Sstevel@tonic-gate */ 5670Sstevel@tonic-gate (void) gettimeofday(&tvgoal, 0); 5680Sstevel@tonic-gate msincr(&tvgoal, msec); 5690Sstevel@tonic-gate } 5700Sstevel@tonic-gate 571*2235Skk112340 /* 572*2235Skk112340 * The event handling loop continues while running is 1. 573*2235Skk112340 * running becomes 0 when either the controlled process has 574*2235Skk112340 * exited successfully or the number of time samples has expired. 575*2235Skk112340 * Otherwise, if an error has occurred, running becomes -1. 576*2235Skk112340 */ 577*2235Skk112340 while (running == 1) { 5780Sstevel@tonic-gate 5790Sstevel@tonic-gate if (Psetrun(pctx->Pr, 0, 0) != 0) { 5800Sstevel@tonic-gate if (pctx->verbose) 5810Sstevel@tonic-gate pctx_error(pctx, fn, 5820Sstevel@tonic-gate gettext("%d: Psetrun\n"), (int)pid); 5830Sstevel@tonic-gate break; 5840Sstevel@tonic-gate } 5850Sstevel@tonic-gate 5860Sstevel@tonic-gate if (msec != 0) { 5870Sstevel@tonic-gate /* 5880Sstevel@tonic-gate * This timing loop attempts to estimate the number 5890Sstevel@tonic-gate * of milliseconds between our "goal" time (when 5900Sstevel@tonic-gate * we should stop the process and run the tick 5910Sstevel@tonic-gate * routine) and the current time. 5920Sstevel@tonic-gate * 5930Sstevel@tonic-gate * If we ever find ourselves running behind i.e. we 5940Sstevel@tonic-gate * missed our goal, then we skip ahead to the next 5950Sstevel@tonic-gate * goal instead. 5960Sstevel@tonic-gate */ 5970Sstevel@tonic-gate do { 5980Sstevel@tonic-gate (void) gettimeofday(&tvnow, 0); 5990Sstevel@tonic-gate if ((mswait = msdiff(&tvgoal, &tvnow)) == 0) { 6000Sstevel@tonic-gate msincr(&tvgoal, msec); 6010Sstevel@tonic-gate /* 6020Sstevel@tonic-gate * Skip ahead to the next goal, unless 6030Sstevel@tonic-gate * there is only one more sample left 6040Sstevel@tonic-gate * to take. 6050Sstevel@tonic-gate */ 6060Sstevel@tonic-gate if (nsamples != 1) 6070Sstevel@tonic-gate nsamples--; 6080Sstevel@tonic-gate } 6090Sstevel@tonic-gate } while (mswait == 0); 6100Sstevel@tonic-gate } 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate (void) Pwait(pctx->Pr, mswait); 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate checkstate: 6150Sstevel@tonic-gate switch (pstate = Pstate(pctx->Pr)) { 6160Sstevel@tonic-gate case PS_RUN: 6170Sstevel@tonic-gate /* 6180Sstevel@tonic-gate * Try again, but wait for up to 5 seconds. 6190Sstevel@tonic-gate */ 6200Sstevel@tonic-gate if (Pstop(pctx->Pr, 5 * MILLISEC) == -1 || 6210Sstevel@tonic-gate (pstate = Pstate(pctx->Pr)) != PS_STOP) { 6220Sstevel@tonic-gate pctx_error(pctx, fn, 6230Sstevel@tonic-gate gettext("%d: won't stop\n"), (int)pid); 6240Sstevel@tonic-gate } 6250Sstevel@tonic-gate break; 6260Sstevel@tonic-gate case PS_STOP: 6270Sstevel@tonic-gate break; 6280Sstevel@tonic-gate case PS_LOST: 6290Sstevel@tonic-gate /* 6300Sstevel@tonic-gate * Lost control - probably execed a setuid/setgid 6310Sstevel@tonic-gate * executable. Try and get control back again, 6320Sstevel@tonic-gate * else bail .. 6330Sstevel@tonic-gate */ 6340Sstevel@tonic-gate (void) Preopen(pctx->Pr); 6350Sstevel@tonic-gate if ((pstate = Pstate(pctx->Pr)) != PS_LOST) 6360Sstevel@tonic-gate goto checkstate; 6370Sstevel@tonic-gate pctx_error(pctx, fn, 6380Sstevel@tonic-gate gettext("%d: execed a program that cannot " 6390Sstevel@tonic-gate "be tracked\n"), (int)pid); 640*2235Skk112340 running = -1; 6410Sstevel@tonic-gate break; 6420Sstevel@tonic-gate case PS_UNDEAD: 6430Sstevel@tonic-gate case PS_DEAD: 6440Sstevel@tonic-gate if (pctx->verbose) 6450Sstevel@tonic-gate pctx_error(pctx, fn, 6460Sstevel@tonic-gate gettext("%d: process terminated\n"), 6470Sstevel@tonic-gate (int)pid); 648*2235Skk112340 running = -1; 6490Sstevel@tonic-gate break; 6500Sstevel@tonic-gate default: 6510Sstevel@tonic-gate if (pctx->verbose) 6520Sstevel@tonic-gate pctx_error(pctx, fn, 6530Sstevel@tonic-gate gettext("%d: process state 0x%x?\n"), 6540Sstevel@tonic-gate (int)pid, pstate); 6550Sstevel@tonic-gate break; 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate if (pstate != PS_STOP) 6590Sstevel@tonic-gate break; 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate pstatus = Pstatus(pctx->Pr); 6620Sstevel@tonic-gate lwpid = pstatus->pr_lwp.pr_lwpid; 6630Sstevel@tonic-gate switch (pstatus->pr_lwp.pr_why) { 6640Sstevel@tonic-gate case PR_REQUESTED: 6650Sstevel@tonic-gate msincr(&tvgoal, msec); 6660Sstevel@tonic-gate if (pstatus->pr_flags & PR_VFORKP) { 6670Sstevel@tonic-gate /* 6680Sstevel@tonic-gate * The process is in a vfork stupor until 6690Sstevel@tonic-gate * its child releases it via an exec. 6700Sstevel@tonic-gate * Don't sample it while it's in this state 6710Sstevel@tonic-gate * - we won't be able to create the agent. 6720Sstevel@tonic-gate */ 6730Sstevel@tonic-gate break; 6740Sstevel@tonic-gate } 6750Sstevel@tonic-gate if (pctx_lwpiterate(pctx, tick) != 0) 676*2235Skk112340 running = -1; 677*2235Skk112340 if (running == 1 && --nsamples == 0) 6780Sstevel@tonic-gate running = 0; 6790Sstevel@tonic-gate break; 6800Sstevel@tonic-gate case PR_SYSENTRY: 6810Sstevel@tonic-gate switch (pstatus->pr_lwp.pr_what) { 6820Sstevel@tonic-gate case SYS_lwp_exit: 6830Sstevel@tonic-gate pctx_begin_syscalls(pctx); 6840Sstevel@tonic-gate (void) pctx->fini_lwp(pctx, 6850Sstevel@tonic-gate pid, lwpid, pctx->uarg); 6860Sstevel@tonic-gate (void) pctx->lwp_exit(pctx, 6870Sstevel@tonic-gate pid, lwpid, pctx->uarg); 6880Sstevel@tonic-gate pctx_end_syscalls(pctx); 6890Sstevel@tonic-gate break; 6900Sstevel@tonic-gate case SYS_exit: 691*2235Skk112340 if (pctx_lwpiterate(pctx, pctx->fini_lwp) 692*2235Skk112340 != 0) 693*2235Skk112340 running = -1; 6940Sstevel@tonic-gate pctx->exit(pctx, pid, lwpid, 6950Sstevel@tonic-gate (int)pstatus->pr_lwp.pr_sysarg[0], 6960Sstevel@tonic-gate pctx->uarg); 697*2235Skk112340 if (running == 1) 698*2235Skk112340 running = 0; 6990Sstevel@tonic-gate break; 7000Sstevel@tonic-gate case SYS_exec: 7010Sstevel@tonic-gate case SYS_execve: 7020Sstevel@tonic-gate (void) pctx_lwpiterate(pctx, pctx->fini_lwp); 7030Sstevel@tonic-gate break; 7040Sstevel@tonic-gate default: 7050Sstevel@tonic-gate pctx_error(pctx, fn, 7060Sstevel@tonic-gate "warning - pid %d sysentry(%d)\n", 7070Sstevel@tonic-gate (int)pid, pstatus->pr_lwp.pr_what); 7080Sstevel@tonic-gate break; 7090Sstevel@tonic-gate } 7100Sstevel@tonic-gate break; 7110Sstevel@tonic-gate case PR_SYSEXIT: 7120Sstevel@tonic-gate switch (pstatus->pr_lwp.pr_what) { 7130Sstevel@tonic-gate case SYS_exec: 7140Sstevel@tonic-gate case SYS_execve: 7150Sstevel@tonic-gate if (pstatus->pr_lwp.pr_errno) { 7160Sstevel@tonic-gate /* 7170Sstevel@tonic-gate * The exec failed completely. 7180Sstevel@tonic-gate * Reinstate the lwps we fini'd 7190Sstevel@tonic-gate * at exec entrance 7200Sstevel@tonic-gate */ 721*2235Skk112340 if (pctx_lwpiterate(pctx, 722*2235Skk112340 pctx->init_lwp) == 0) 723*2235Skk112340 running = 1; 724*2235Skk112340 else 725*2235Skk112340 running = -1; 7260Sstevel@tonic-gate break; 7270Sstevel@tonic-gate } 7280Sstevel@tonic-gate if (pctx->exec == (pctx_sysc_execfn_t *) 7290Sstevel@tonic-gate default_int) { 7300Sstevel@tonic-gate running = 0; 7310Sstevel@tonic-gate break; 7320Sstevel@tonic-gate } 7330Sstevel@tonic-gate (void) memcpy(&psinfo, 7340Sstevel@tonic-gate Ppsinfo(pctx->Pr), sizeof (psinfo)); 7350Sstevel@tonic-gate proc_unctrl_psinfo(&psinfo); 7360Sstevel@tonic-gate pctx_begin_syscalls(pctx); 737*2235Skk112340 if (pctx->exec(pctx, pid, lwpid, 738*2235Skk112340 psinfo.pr_psargs, pctx->uarg) != 0) 739*2235Skk112340 running = -1; 740*2235Skk112340 if (running == 1 && pctx->init_lwp(pctx, 741*2235Skk112340 pid, 1, pctx->uarg) != 0) 742*2235Skk112340 running = -1; 7430Sstevel@tonic-gate pctx_end_syscalls(pctx); 7440Sstevel@tonic-gate break; 7450Sstevel@tonic-gate case SYS_lwp_create: 7460Sstevel@tonic-gate if (pstatus->pr_lwp.pr_errno || 7470Sstevel@tonic-gate pstatus->pr_lwp.pr_rval1) 7480Sstevel@tonic-gate break; 7490Sstevel@tonic-gate pctx_begin_syscalls(pctx); 750*2235Skk112340 if (pctx->init_lwp(pctx, pid, lwpid, 751*2235Skk112340 pctx->uarg) != 0) 752*2235Skk112340 running = -1; 753*2235Skk112340 if (running == 1 && pctx->lwp_create(pctx, 754*2235Skk112340 pid, lwpid, pctx->uarg) != 0) 755*2235Skk112340 running = -1; 7560Sstevel@tonic-gate pctx_end_syscalls(pctx); 7570Sstevel@tonic-gate break; 7580Sstevel@tonic-gate case SYS_forkall: 7590Sstevel@tonic-gate case SYS_vfork: 7600Sstevel@tonic-gate case SYS_fork1: 7610Sstevel@tonic-gate if (pstatus->pr_lwp.pr_errno) 7620Sstevel@tonic-gate break; 7630Sstevel@tonic-gate (void) fflush(NULL); 7640Sstevel@tonic-gate switch (fork1()) { 7650Sstevel@tonic-gate pid_t ppid; 7660Sstevel@tonic-gate int wascreated; 7670Sstevel@tonic-gate pctx_sysc_forkfn_t *forkfn; 7680Sstevel@tonic-gate case 0: 7690Sstevel@tonic-gate ppid = pid; 7700Sstevel@tonic-gate pid = pstatus->pr_lwp.pr_rval1; 7710Sstevel@tonic-gate wascreated = pctx->created; 7720Sstevel@tonic-gate forkfn = pctx->fork; 7730Sstevel@tonic-gate pctx_free(pctx); 7740Sstevel@tonic-gate pctx = pctx_capture(pid, pctx->uarg, 7750Sstevel@tonic-gate pctx->verbose, pctx->errfn); 7760Sstevel@tonic-gate if (pctx != NULL) { 7770Sstevel@tonic-gate if (wascreated) { 7780Sstevel@tonic-gate /* 7790Sstevel@tonic-gate * Set kill on last 7800Sstevel@tonic-gate * close so -all- 7810Sstevel@tonic-gate * children die. 7820Sstevel@tonic-gate */ 7830Sstevel@tonic-gate pctx->created = 1; 7840Sstevel@tonic-gate (void) Psetflags( 7850Sstevel@tonic-gate pctx->Pr, PR_KLC); 7860Sstevel@tonic-gate } 7870Sstevel@tonic-gate (*forkfn)(pctx, ppid, pid, 7880Sstevel@tonic-gate lwpid, pctx->uarg); 7890Sstevel@tonic-gate pctx_release(pctx); 790*2235Skk112340 _exit(0); 791*2235Skk112340 } else { 792*2235Skk112340 _exit(1); 7930Sstevel@tonic-gate } 7940Sstevel@tonic-gate /*NOTREACHED*/ 7950Sstevel@tonic-gate case -1: 7960Sstevel@tonic-gate pctx_error(pctx, fn, 7970Sstevel@tonic-gate "cannot follow pid %d: %s\n", 7980Sstevel@tonic-gate (int)pstatus->pr_lwp.pr_rval1, 7990Sstevel@tonic-gate strerror(errno)); 8000Sstevel@tonic-gate break; 8010Sstevel@tonic-gate default: 8020Sstevel@tonic-gate break; 8030Sstevel@tonic-gate } 8040Sstevel@tonic-gate break; 8050Sstevel@tonic-gate default: 8060Sstevel@tonic-gate pctx_error(pctx, fn, gettext( 8070Sstevel@tonic-gate "warning - pid %d sysexit(%d)\n"), 8080Sstevel@tonic-gate (int)pid, pstatus->pr_lwp.pr_what); 8090Sstevel@tonic-gate break; 8100Sstevel@tonic-gate } 8110Sstevel@tonic-gate break; 8120Sstevel@tonic-gate case PR_SIGNALLED: 8130Sstevel@tonic-gate if (pctx->verbose) 8140Sstevel@tonic-gate pctx_error(pctx, fn, 8150Sstevel@tonic-gate gettext("pid %d - signalled\n"), (int)pid); 8160Sstevel@tonic-gate break; 8170Sstevel@tonic-gate case PR_JOBCONTROL: 8180Sstevel@tonic-gate if (pctx->verbose) 8190Sstevel@tonic-gate pctx_error(pctx, fn, 8200Sstevel@tonic-gate gettext("pid %d - job control stop\n"), 8210Sstevel@tonic-gate (int)pid); 822*2235Skk112340 running = -1; 8230Sstevel@tonic-gate break; 8240Sstevel@tonic-gate case PR_FAULTED: 8250Sstevel@tonic-gate if (pctx->verbose) 8260Sstevel@tonic-gate pctx_error(pctx, fn, 8270Sstevel@tonic-gate gettext("pid %d - faulted\n"), (int)pid); 8280Sstevel@tonic-gate break; 8290Sstevel@tonic-gate case PR_SUSPENDED: 8300Sstevel@tonic-gate if (pctx->verbose) 8310Sstevel@tonic-gate pctx_error(pctx, fn, 8320Sstevel@tonic-gate gettext("pid %d - suspended\n"), (int)pid); 8330Sstevel@tonic-gate break; 8340Sstevel@tonic-gate case PR_CHECKPOINT: 8350Sstevel@tonic-gate if (pctx->verbose) 8360Sstevel@tonic-gate pctx_error(pctx, fn, 8370Sstevel@tonic-gate gettext("pid %d - checkpoint\n"), 8380Sstevel@tonic-gate (int)pid); 8390Sstevel@tonic-gate break; 8400Sstevel@tonic-gate default: 8410Sstevel@tonic-gate if (pctx->verbose) 8420Sstevel@tonic-gate pctx_error(pctx, fn, 8430Sstevel@tonic-gate gettext("pid %d - reason %d\n"), 8440Sstevel@tonic-gate (int)pid, pstatus->pr_lwp.pr_why); 845*2235Skk112340 running = -1; 8460Sstevel@tonic-gate break; 8470Sstevel@tonic-gate } 8480Sstevel@tonic-gate } 8490Sstevel@tonic-gate 8500Sstevel@tonic-gate bailout: 8510Sstevel@tonic-gate (void) signal(SIGCHLD, sigsaved); 852*2235Skk112340 853*2235Skk112340 switch (running) { 854*2235Skk112340 case 0: 8550Sstevel@tonic-gate return (0); 856*2235Skk112340 case -1: 857*2235Skk112340 return (-1); 858*2235Skk112340 default: 859*2235Skk112340 pctx_error(pctx, fn, gettext("lost control of pid %d\n"), 860*2235Skk112340 (int)pid); 861*2235Skk112340 pctx_free(pctx); 862*2235Skk112340 return (-1); 863*2235Skk112340 } 8640Sstevel@tonic-gate } 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate /* 8670Sstevel@tonic-gate * Execute the private 'cpc' system call in the context of the 8680Sstevel@tonic-gate * controlled process. 8690Sstevel@tonic-gate */ 8700Sstevel@tonic-gate int 8710Sstevel@tonic-gate __pctx_cpc(pctx_t *pctx, cpc_t *cpc, 8720Sstevel@tonic-gate int cmd, id_t lwpid, void *data1, void *data2, void *data3, int bufsize) 8730Sstevel@tonic-gate { 8740Sstevel@tonic-gate sysret_t rval; 8750Sstevel@tonic-gate argdes_t argd[5]; 8760Sstevel@tonic-gate argdes_t *adp = &argd[0]; 8770Sstevel@tonic-gate int error; 8780Sstevel@tonic-gate 8790Sstevel@tonic-gate /* 8800Sstevel@tonic-gate * Keep track of the relationship between cpc_t and pctx_t here. 8810Sstevel@tonic-gate * We store the last cpc_t used by libpctx, so that when this pctx is 8820Sstevel@tonic-gate * destroyed, libpctx can notify libcpc. 8830Sstevel@tonic-gate */ 8840Sstevel@tonic-gate if (pctx->cpc != NULL && pctx->cpc != cpc && pctx_cpc_callback != NULL) 8850Sstevel@tonic-gate (*pctx_cpc_callback)(pctx->cpc, pctx); 8860Sstevel@tonic-gate pctx->cpc = cpc; 8870Sstevel@tonic-gate 8880Sstevel@tonic-gate /* 8890Sstevel@tonic-gate * cmd and lwpid are passed in by value no matter what the command is. 8900Sstevel@tonic-gate */ 8910Sstevel@tonic-gate adp->arg_value = cmd; 8920Sstevel@tonic-gate adp->arg_object = NULL; 8930Sstevel@tonic-gate adp->arg_type = AT_BYVAL; 8940Sstevel@tonic-gate adp->arg_inout = AI_INPUT; 8950Sstevel@tonic-gate adp->arg_size = 0; 8960Sstevel@tonic-gate adp++; 8970Sstevel@tonic-gate 8980Sstevel@tonic-gate adp->arg_value = lwpid; 8990Sstevel@tonic-gate adp->arg_object = NULL; 9000Sstevel@tonic-gate adp->arg_type = AT_BYVAL; 9010Sstevel@tonic-gate adp->arg_inout = AI_INPUT; 9020Sstevel@tonic-gate adp->arg_size = 0; 9030Sstevel@tonic-gate adp++; 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate switch (cmd) { 9060Sstevel@tonic-gate case CPC_BIND: 9070Sstevel@tonic-gate adp->arg_value = 0; 9080Sstevel@tonic-gate adp->arg_object = data1; 9090Sstevel@tonic-gate adp->arg_type = AT_BYREF; 9100Sstevel@tonic-gate adp->arg_inout = AI_INPUT; 9110Sstevel@tonic-gate adp->arg_size = (size_t)data2; 9120Sstevel@tonic-gate adp++; 9130Sstevel@tonic-gate 9140Sstevel@tonic-gate adp->arg_value = (size_t)data2; 9150Sstevel@tonic-gate adp->arg_object = NULL; 9160Sstevel@tonic-gate adp->arg_type = AT_BYVAL; 9170Sstevel@tonic-gate adp->arg_inout = AI_INPUT; 9180Sstevel@tonic-gate adp->arg_size = 0; 9190Sstevel@tonic-gate adp++; 9200Sstevel@tonic-gate 9210Sstevel@tonic-gate adp->arg_value = 0; 9220Sstevel@tonic-gate adp->arg_object = data3; 9230Sstevel@tonic-gate adp->arg_type = AT_BYREF; 9240Sstevel@tonic-gate adp->arg_inout = AI_INOUT; 9250Sstevel@tonic-gate adp->arg_size = sizeof (int); 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate break; 9280Sstevel@tonic-gate case CPC_SAMPLE: 9290Sstevel@tonic-gate adp->arg_value = 0; 9300Sstevel@tonic-gate adp->arg_object = data1; 9310Sstevel@tonic-gate adp->arg_type = AT_BYREF; 9320Sstevel@tonic-gate adp->arg_inout = AI_OUTPUT; 9330Sstevel@tonic-gate adp->arg_size = bufsize; 9340Sstevel@tonic-gate adp++; 9350Sstevel@tonic-gate 9360Sstevel@tonic-gate adp->arg_value = 0; 9370Sstevel@tonic-gate adp->arg_object = data2; 9380Sstevel@tonic-gate adp->arg_type = AT_BYREF; 9390Sstevel@tonic-gate adp->arg_inout = AI_OUTPUT; 9400Sstevel@tonic-gate adp->arg_size = sizeof (hrtime_t); 9410Sstevel@tonic-gate adp++; 9420Sstevel@tonic-gate 9430Sstevel@tonic-gate adp->arg_value = 0; 9440Sstevel@tonic-gate adp->arg_object = data3; 9450Sstevel@tonic-gate adp->arg_type = AT_BYREF; 9460Sstevel@tonic-gate adp->arg_inout = AI_OUTPUT; 9470Sstevel@tonic-gate adp->arg_size = sizeof (uint64_t); 9480Sstevel@tonic-gate 9490Sstevel@tonic-gate break; 9500Sstevel@tonic-gate default: 9510Sstevel@tonic-gate adp->arg_value = 0; 9520Sstevel@tonic-gate adp->arg_object = 0; 9530Sstevel@tonic-gate adp->arg_type = AT_BYVAL; 9540Sstevel@tonic-gate adp->arg_inout = AI_INPUT; 9550Sstevel@tonic-gate adp->arg_size = 0; 9560Sstevel@tonic-gate adp++; 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate adp->arg_value = 0; 9590Sstevel@tonic-gate adp->arg_object = 0; 9600Sstevel@tonic-gate adp->arg_type = AT_BYVAL; 9610Sstevel@tonic-gate adp->arg_inout = AI_INPUT; 9620Sstevel@tonic-gate adp->arg_size = 0; 9630Sstevel@tonic-gate adp++; 9640Sstevel@tonic-gate 9650Sstevel@tonic-gate adp->arg_value = 0; 9660Sstevel@tonic-gate adp->arg_object = 0; 9670Sstevel@tonic-gate adp->arg_type = AT_BYVAL; 9680Sstevel@tonic-gate adp->arg_inout = AI_INPUT; 9690Sstevel@tonic-gate adp->arg_size = 0; 9700Sstevel@tonic-gate 9710Sstevel@tonic-gate break; 9720Sstevel@tonic-gate } 9730Sstevel@tonic-gate 9740Sstevel@tonic-gate error = Psyscall(pctx->Pr, &rval, SYS_cpc, 5, &argd[0]); 9750Sstevel@tonic-gate 9760Sstevel@tonic-gate if (error) { 9770Sstevel@tonic-gate errno = error > 0 ? error : ENOSYS; 9780Sstevel@tonic-gate return (-1); 9790Sstevel@tonic-gate } 9800Sstevel@tonic-gate return (rval.sys_rval1); 9810Sstevel@tonic-gate } 9820Sstevel@tonic-gate 9830Sstevel@tonic-gate /* 9840Sstevel@tonic-gate * libcpc-private hook used to register a callback. The callback is used to 9850Sstevel@tonic-gate * notify libcpc when a pctx handle is invalidated. 9860Sstevel@tonic-gate */ 9870Sstevel@tonic-gate void 9880Sstevel@tonic-gate __pctx_cpc_register_callback(void (*arg)(struct __cpc *, struct __pctx *)) 9890Sstevel@tonic-gate { 9900Sstevel@tonic-gate pctx_cpc_callback = arg; 9910Sstevel@tonic-gate } 992