1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * This file contains a set of generic routines for periodically 31*7c478bd9Sstevel@tonic-gate * sampling the state of another process, or tree of processes. 32*7c478bd9Sstevel@tonic-gate * 33*7c478bd9Sstevel@tonic-gate * It is built upon the infrastructure provided by libproc. 34*7c478bd9Sstevel@tonic-gate */ 35*7c478bd9Sstevel@tonic-gate 36*7c478bd9Sstevel@tonic-gate #include <sys/wait.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/syscall.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 39*7c478bd9Sstevel@tonic-gate #include <libproc.h> 40*7c478bd9Sstevel@tonic-gate #include <stdio.h> 41*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 42*7c478bd9Sstevel@tonic-gate #include <errno.h> 43*7c478bd9Sstevel@tonic-gate #include <unistd.h> 44*7c478bd9Sstevel@tonic-gate #include <signal.h> 45*7c478bd9Sstevel@tonic-gate #include <string.h> 46*7c478bd9Sstevel@tonic-gate #include <strings.h> 47*7c478bd9Sstevel@tonic-gate #include <limits.h> 48*7c478bd9Sstevel@tonic-gate #include <ctype.h> 49*7c478bd9Sstevel@tonic-gate #include <libintl.h> 50*7c478bd9Sstevel@tonic-gate #include <libcpc.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/cpc_impl.h> 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate #include "libpctx.h" 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate struct __pctx { 56*7c478bd9Sstevel@tonic-gate pctx_errfn_t *errfn; 57*7c478bd9Sstevel@tonic-gate struct ps_prochandle *Pr; 58*7c478bd9Sstevel@tonic-gate void *uarg; 59*7c478bd9Sstevel@tonic-gate pctx_sysc_execfn_t *exec; 60*7c478bd9Sstevel@tonic-gate pctx_sysc_forkfn_t *fork; 61*7c478bd9Sstevel@tonic-gate pctx_sysc_exitfn_t *exit; 62*7c478bd9Sstevel@tonic-gate pctx_sysc_lwp_createfn_t *lwp_create; 63*7c478bd9Sstevel@tonic-gate pctx_init_lwpfn_t *init_lwp; 64*7c478bd9Sstevel@tonic-gate pctx_fini_lwpfn_t *fini_lwp; 65*7c478bd9Sstevel@tonic-gate pctx_sysc_lwp_exitfn_t *lwp_exit; 66*7c478bd9Sstevel@tonic-gate int verbose; 67*7c478bd9Sstevel@tonic-gate int created; 68*7c478bd9Sstevel@tonic-gate int sigblocked; 69*7c478bd9Sstevel@tonic-gate sigset_t savedset; 70*7c478bd9Sstevel@tonic-gate cpc_t *cpc; 71*7c478bd9Sstevel@tonic-gate }; 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate static void (*pctx_cpc_callback)(cpc_t *cpc, struct __pctx *pctx); 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate static void 76*7c478bd9Sstevel@tonic-gate pctx_default_errfn(const char *fn, const char *fmt, va_list ap) 77*7c478bd9Sstevel@tonic-gate { 78*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "libpctx: pctx_%s: ", fn); 79*7c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap); 80*7c478bd9Sstevel@tonic-gate } 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE3*/ 83*7c478bd9Sstevel@tonic-gate static void 84*7c478bd9Sstevel@tonic-gate pctx_error(pctx_t *pctx, const char *fn, const char *fmt, ...) 85*7c478bd9Sstevel@tonic-gate { 86*7c478bd9Sstevel@tonic-gate va_list ap; 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate va_start(ap, fmt); 89*7c478bd9Sstevel@tonic-gate pctx->errfn(fn, fmt, ap); 90*7c478bd9Sstevel@tonic-gate va_end(ap); 91*7c478bd9Sstevel@tonic-gate } 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate /* 94*7c478bd9Sstevel@tonic-gate * Create a new process and bind the user args for it 95*7c478bd9Sstevel@tonic-gate */ 96*7c478bd9Sstevel@tonic-gate pctx_t * 97*7c478bd9Sstevel@tonic-gate pctx_create( 98*7c478bd9Sstevel@tonic-gate const char *filename, 99*7c478bd9Sstevel@tonic-gate char *const *argv, 100*7c478bd9Sstevel@tonic-gate void *arg, 101*7c478bd9Sstevel@tonic-gate int verbose, 102*7c478bd9Sstevel@tonic-gate pctx_errfn_t *errfn) 103*7c478bd9Sstevel@tonic-gate { 104*7c478bd9Sstevel@tonic-gate static const char fn[] = "create"; 105*7c478bd9Sstevel@tonic-gate int err; 106*7c478bd9Sstevel@tonic-gate pctx_t *pctx; 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate pctx = calloc(1, sizeof (*pctx)); 109*7c478bd9Sstevel@tonic-gate pctx->uarg = arg; 110*7c478bd9Sstevel@tonic-gate pctx->verbose = verbose; 111*7c478bd9Sstevel@tonic-gate pctx->errfn = errfn ? errfn : pctx_default_errfn; 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate if ((pctx->Pr = Pcreate(filename, argv, &err, 0, 0)) == NULL) { 114*7c478bd9Sstevel@tonic-gate switch (err) { 115*7c478bd9Sstevel@tonic-gate case C_PERM: 116*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, gettext("cannot trace set-id or " 117*7c478bd9Sstevel@tonic-gate "unreadable program '%s'\n"), filename); 118*7c478bd9Sstevel@tonic-gate break; 119*7c478bd9Sstevel@tonic-gate case C_LP64: 120*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, gettext("cannot control LP64 " 121*7c478bd9Sstevel@tonic-gate "program '%s'\n"), filename); 122*7c478bd9Sstevel@tonic-gate break; 123*7c478bd9Sstevel@tonic-gate case C_NOEXEC: 124*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, gettext("cannot execute " 125*7c478bd9Sstevel@tonic-gate "program '%s'\n"), filename); 126*7c478bd9Sstevel@tonic-gate break; 127*7c478bd9Sstevel@tonic-gate case C_NOENT: 128*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, gettext("cannot find" 129*7c478bd9Sstevel@tonic-gate "program '%s'\n"), filename); 130*7c478bd9Sstevel@tonic-gate break; 131*7c478bd9Sstevel@tonic-gate case C_FORK: 132*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, gettext("cannot fork, " 133*7c478bd9Sstevel@tonic-gate "program '%s'\n"), filename); 134*7c478bd9Sstevel@tonic-gate break; 135*7c478bd9Sstevel@tonic-gate default: 136*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, gettext("%s, program '%s'\n"), 137*7c478bd9Sstevel@tonic-gate Pcreate_error(err), filename); 138*7c478bd9Sstevel@tonic-gate break; 139*7c478bd9Sstevel@tonic-gate } 140*7c478bd9Sstevel@tonic-gate free(pctx); 141*7c478bd9Sstevel@tonic-gate return (NULL); 142*7c478bd9Sstevel@tonic-gate } 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate if (Psysentry(pctx->Pr, SYS_exit, 1) == -1) { 145*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 146*7c478bd9Sstevel@tonic-gate gettext("can't stop-on-exit() program '%s'\n"), filename); 147*7c478bd9Sstevel@tonic-gate Prelease(pctx->Pr, PRELEASE_KILL); 148*7c478bd9Sstevel@tonic-gate free(pctx); 149*7c478bd9Sstevel@tonic-gate return (NULL); 150*7c478bd9Sstevel@tonic-gate } 151*7c478bd9Sstevel@tonic-gate /* 152*7c478bd9Sstevel@tonic-gate * Set kill-on-last-close so the controlled process 153*7c478bd9Sstevel@tonic-gate * dies if we die. 154*7c478bd9Sstevel@tonic-gate */ 155*7c478bd9Sstevel@tonic-gate pctx->created = 1; 156*7c478bd9Sstevel@tonic-gate (void) Psetflags(pctx->Pr, PR_KLC); 157*7c478bd9Sstevel@tonic-gate (void) pctx_set_events(pctx, PCTX_NULL_EVENT); 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate return (pctx); 160*7c478bd9Sstevel@tonic-gate } 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate /* 163*7c478bd9Sstevel@tonic-gate * Capture an existing process and bind the user args for it 164*7c478bd9Sstevel@tonic-gate */ 165*7c478bd9Sstevel@tonic-gate pctx_t * 166*7c478bd9Sstevel@tonic-gate pctx_capture(pid_t pid, void *arg, int verbose, pctx_errfn_t *errfn) 167*7c478bd9Sstevel@tonic-gate { 168*7c478bd9Sstevel@tonic-gate static const char fn[] = "capture"; 169*7c478bd9Sstevel@tonic-gate int err; 170*7c478bd9Sstevel@tonic-gate pctx_t *pctx; 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate pctx = calloc(1, sizeof (*pctx)); 173*7c478bd9Sstevel@tonic-gate pctx->uarg = arg; 174*7c478bd9Sstevel@tonic-gate pctx->verbose = verbose; 175*7c478bd9Sstevel@tonic-gate pctx->errfn = errfn ? errfn : pctx_default_errfn; 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate if ((pctx->Pr = Pgrab(pid, 0, &err)) == NULL) { 178*7c478bd9Sstevel@tonic-gate switch (err) { 179*7c478bd9Sstevel@tonic-gate case G_NOPROC: 180*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 181*7c478bd9Sstevel@tonic-gate gettext("pid %d doesn't exist\n"), (int)pid); 182*7c478bd9Sstevel@tonic-gate break; 183*7c478bd9Sstevel@tonic-gate case G_ZOMB: 184*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 185*7c478bd9Sstevel@tonic-gate gettext("pid %d is a zombie\n"), (int)pid); 186*7c478bd9Sstevel@tonic-gate break; 187*7c478bd9Sstevel@tonic-gate case G_PERM: 188*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 189*7c478bd9Sstevel@tonic-gate gettext("pid %d: permission denied\n"), (int)pid); 190*7c478bd9Sstevel@tonic-gate break; 191*7c478bd9Sstevel@tonic-gate case G_BUSY: 192*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 193*7c478bd9Sstevel@tonic-gate gettext("pid %d is already being traced\n"), 194*7c478bd9Sstevel@tonic-gate (int)pid); 195*7c478bd9Sstevel@tonic-gate break; 196*7c478bd9Sstevel@tonic-gate case G_SYS: 197*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 198*7c478bd9Sstevel@tonic-gate gettext("pid %d is a system process\n"), (int)pid); 199*7c478bd9Sstevel@tonic-gate break; 200*7c478bd9Sstevel@tonic-gate case G_SELF: 201*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 202*7c478bd9Sstevel@tonic-gate gettext("cannot capture self!\n")); 203*7c478bd9Sstevel@tonic-gate break; 204*7c478bd9Sstevel@tonic-gate case G_LP64: 205*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, gettext("cannot control LP64 " 206*7c478bd9Sstevel@tonic-gate "process, pid %d\n"), (int)pid); 207*7c478bd9Sstevel@tonic-gate break; 208*7c478bd9Sstevel@tonic-gate default: 209*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, gettext("%s: pid %d\n"), 210*7c478bd9Sstevel@tonic-gate Pgrab_error(err), (int)pid); 211*7c478bd9Sstevel@tonic-gate break; 212*7c478bd9Sstevel@tonic-gate } 213*7c478bd9Sstevel@tonic-gate free(pctx); 214*7c478bd9Sstevel@tonic-gate return (NULL); 215*7c478bd9Sstevel@tonic-gate } 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate if (Psysentry(pctx->Pr, SYS_exit, 1) == -1) { 218*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 219*7c478bd9Sstevel@tonic-gate gettext("can't stop-on-exit() pid %d\n"), (int)pid); 220*7c478bd9Sstevel@tonic-gate Prelease(pctx->Pr, PRELEASE_CLEAR); 221*7c478bd9Sstevel@tonic-gate free(pctx); 222*7c478bd9Sstevel@tonic-gate return (NULL); 223*7c478bd9Sstevel@tonic-gate } 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate /* 226*7c478bd9Sstevel@tonic-gate * Set run-on-last-close so the controlled process 227*7c478bd9Sstevel@tonic-gate * runs even if we die on a signal. This is because 228*7c478bd9Sstevel@tonic-gate * we grabbed an existing process - it would be impolite 229*7c478bd9Sstevel@tonic-gate * to cause it to die if we exit prematurely. 230*7c478bd9Sstevel@tonic-gate */ 231*7c478bd9Sstevel@tonic-gate pctx->created = 0; 232*7c478bd9Sstevel@tonic-gate (void) Psetflags(pctx->Pr, PR_RLC); 233*7c478bd9Sstevel@tonic-gate (void) pctx_set_events(pctx, PCTX_NULL_EVENT); 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate return (pctx); 236*7c478bd9Sstevel@tonic-gate } 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 239*7c478bd9Sstevel@tonic-gate static void 240*7c478bd9Sstevel@tonic-gate default_void(pctx_t *pctx) 241*7c478bd9Sstevel@tonic-gate {} 242*7c478bd9Sstevel@tonic-gate 243*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 244*7c478bd9Sstevel@tonic-gate static int 245*7c478bd9Sstevel@tonic-gate default_int(pctx_t *pctx) 246*7c478bd9Sstevel@tonic-gate { 247*7c478bd9Sstevel@tonic-gate return (0); 248*7c478bd9Sstevel@tonic-gate } 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate int 251*7c478bd9Sstevel@tonic-gate pctx_set_events(pctx_t *pctx, ...) 252*7c478bd9Sstevel@tonic-gate { 253*7c478bd9Sstevel@tonic-gate static const char fn[] = "set_events"; 254*7c478bd9Sstevel@tonic-gate va_list pvar; 255*7c478bd9Sstevel@tonic-gate int error = 0; 256*7c478bd9Sstevel@tonic-gate pctx_event_t event; 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate va_start(pvar, pctx); 259*7c478bd9Sstevel@tonic-gate do { 260*7c478bd9Sstevel@tonic-gate switch (event = (pctx_event_t)va_arg(pvar, pctx_event_t)) { 261*7c478bd9Sstevel@tonic-gate case PCTX_NULL_EVENT: 262*7c478bd9Sstevel@tonic-gate break; 263*7c478bd9Sstevel@tonic-gate case PCTX_SYSC_EXEC_EVENT: 264*7c478bd9Sstevel@tonic-gate pctx->exec = (pctx_sysc_execfn_t *) 265*7c478bd9Sstevel@tonic-gate va_arg(pvar, pctx_sysc_execfn_t *); 266*7c478bd9Sstevel@tonic-gate break; 267*7c478bd9Sstevel@tonic-gate case PCTX_SYSC_FORK_EVENT: 268*7c478bd9Sstevel@tonic-gate pctx->fork = (pctx_sysc_forkfn_t *) 269*7c478bd9Sstevel@tonic-gate va_arg(pvar, pctx_sysc_forkfn_t *); 270*7c478bd9Sstevel@tonic-gate break; 271*7c478bd9Sstevel@tonic-gate case PCTX_SYSC_EXIT_EVENT: /* always intercepted */ 272*7c478bd9Sstevel@tonic-gate pctx->exit = (pctx_sysc_exitfn_t *) 273*7c478bd9Sstevel@tonic-gate va_arg(pvar, pctx_sysc_exitfn_t *); 274*7c478bd9Sstevel@tonic-gate break; 275*7c478bd9Sstevel@tonic-gate case PCTX_SYSC_LWP_CREATE_EVENT: 276*7c478bd9Sstevel@tonic-gate pctx->lwp_create = (pctx_sysc_lwp_createfn_t *) 277*7c478bd9Sstevel@tonic-gate va_arg(pvar, pctx_sysc_lwp_createfn_t *); 278*7c478bd9Sstevel@tonic-gate break; 279*7c478bd9Sstevel@tonic-gate case PCTX_INIT_LWP_EVENT: 280*7c478bd9Sstevel@tonic-gate pctx->init_lwp = (pctx_init_lwpfn_t *) 281*7c478bd9Sstevel@tonic-gate va_arg(pvar, pctx_init_lwpfn_t *); 282*7c478bd9Sstevel@tonic-gate break; 283*7c478bd9Sstevel@tonic-gate case PCTX_FINI_LWP_EVENT: 284*7c478bd9Sstevel@tonic-gate pctx->fini_lwp = (pctx_fini_lwpfn_t *) 285*7c478bd9Sstevel@tonic-gate va_arg(pvar, pctx_fini_lwpfn_t *); 286*7c478bd9Sstevel@tonic-gate break; 287*7c478bd9Sstevel@tonic-gate case PCTX_SYSC_LWP_EXIT_EVENT: 288*7c478bd9Sstevel@tonic-gate pctx->lwp_exit = (pctx_sysc_lwp_exitfn_t *) 289*7c478bd9Sstevel@tonic-gate va_arg(pvar, pctx_sysc_lwp_exitfn_t *); 290*7c478bd9Sstevel@tonic-gate break; 291*7c478bd9Sstevel@tonic-gate default: 292*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 293*7c478bd9Sstevel@tonic-gate gettext("unknown event type %x\n"), event); 294*7c478bd9Sstevel@tonic-gate error = -1; 295*7c478bd9Sstevel@tonic-gate break; 296*7c478bd9Sstevel@tonic-gate } 297*7c478bd9Sstevel@tonic-gate } while (event != PCTX_NULL_EVENT && error == 0); 298*7c478bd9Sstevel@tonic-gate va_end(pvar); 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate if (error != 0) 301*7c478bd9Sstevel@tonic-gate return (error); 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate if (pctx->exec == NULL) 304*7c478bd9Sstevel@tonic-gate pctx->exec = (pctx_sysc_execfn_t *)default_int; 305*7c478bd9Sstevel@tonic-gate if (pctx->fork == NULL) 306*7c478bd9Sstevel@tonic-gate pctx->fork = (pctx_sysc_forkfn_t *)default_void; 307*7c478bd9Sstevel@tonic-gate if (pctx->exit == NULL) 308*7c478bd9Sstevel@tonic-gate pctx->exit = (pctx_sysc_exitfn_t *)default_void; 309*7c478bd9Sstevel@tonic-gate if (pctx->lwp_create == NULL) 310*7c478bd9Sstevel@tonic-gate pctx->lwp_create = (pctx_sysc_lwp_createfn_t *)default_int; 311*7c478bd9Sstevel@tonic-gate if (pctx->init_lwp == NULL) 312*7c478bd9Sstevel@tonic-gate pctx->init_lwp = (pctx_init_lwpfn_t *)default_int; 313*7c478bd9Sstevel@tonic-gate if (pctx->fini_lwp == NULL) 314*7c478bd9Sstevel@tonic-gate pctx->fini_lwp = (pctx_fini_lwpfn_t *)default_int; 315*7c478bd9Sstevel@tonic-gate if (pctx->lwp_exit == NULL) 316*7c478bd9Sstevel@tonic-gate pctx->lwp_exit = (pctx_sysc_lwp_exitfn_t *)default_int; 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate if (pctx->fork != (pctx_sysc_forkfn_t *)default_void) { 319*7c478bd9Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_forkall, 1); 320*7c478bd9Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_vfork, 1); 321*7c478bd9Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_fork1, 1); 322*7c478bd9Sstevel@tonic-gate if (Psetflags(pctx->Pr, PR_FORK) == -1) 323*7c478bd9Sstevel@tonic-gate error = -1; 324*7c478bd9Sstevel@tonic-gate } else { 325*7c478bd9Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_forkall, 0); 326*7c478bd9Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_vfork, 0); 327*7c478bd9Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_fork1, 0); 328*7c478bd9Sstevel@tonic-gate if (Punsetflags(pctx->Pr, PR_FORK) == -1) 329*7c478bd9Sstevel@tonic-gate error = -1; 330*7c478bd9Sstevel@tonic-gate } 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate /* 333*7c478bd9Sstevel@tonic-gate * exec causes termination of all but the exec-ing lwp, 334*7c478bd9Sstevel@tonic-gate * and resets the lwpid to one in the new address space. 335*7c478bd9Sstevel@tonic-gate */ 336*7c478bd9Sstevel@tonic-gate if (pctx->exec != (pctx_sysc_execfn_t *)default_int || 337*7c478bd9Sstevel@tonic-gate pctx->fini_lwp != (pctx_fini_lwpfn_t *)default_int || 338*7c478bd9Sstevel@tonic-gate pctx->init_lwp != (pctx_init_lwpfn_t *)default_int) { 339*7c478bd9Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_exec, 1); 340*7c478bd9Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_execve, 1); 341*7c478bd9Sstevel@tonic-gate (void) Psysentry(pctx->Pr, SYS_exec, 1); 342*7c478bd9Sstevel@tonic-gate (void) Psysentry(pctx->Pr, SYS_execve, 1); 343*7c478bd9Sstevel@tonic-gate } else { 344*7c478bd9Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_exec, 0); 345*7c478bd9Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_execve, 0); 346*7c478bd9Sstevel@tonic-gate (void) Psysentry(pctx->Pr, SYS_exec, 0); 347*7c478bd9Sstevel@tonic-gate (void) Psysentry(pctx->Pr, SYS_execve, 0); 348*7c478bd9Sstevel@tonic-gate } 349*7c478bd9Sstevel@tonic-gate 350*7c478bd9Sstevel@tonic-gate (void) Psysexit(pctx->Pr, SYS_lwp_create, 351*7c478bd9Sstevel@tonic-gate pctx->lwp_create != (pctx_sysc_lwp_createfn_t *)default_int || 352*7c478bd9Sstevel@tonic-gate pctx->init_lwp != (pctx_init_lwpfn_t *)default_int); 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate (void) Psysentry(pctx->Pr, SYS_lwp_exit, 355*7c478bd9Sstevel@tonic-gate pctx->lwp_exit != (pctx_sysc_lwp_exitfn_t *)default_int || 356*7c478bd9Sstevel@tonic-gate pctx->fini_lwp != (pctx_fini_lwpfn_t *)default_int); 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate return (0); 359*7c478bd9Sstevel@tonic-gate } 360*7c478bd9Sstevel@tonic-gate 361*7c478bd9Sstevel@tonic-gate static sigset_t termsig; 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate static void 364*7c478bd9Sstevel@tonic-gate __libpctx_init(void) 365*7c478bd9Sstevel@tonic-gate { 366*7c478bd9Sstevel@tonic-gate /* 367*7c478bd9Sstevel@tonic-gate * Initialize the signal set used to shield ourselves from 368*7c478bd9Sstevel@tonic-gate * death-by-terminal-signal while the agent lwp is running. 369*7c478bd9Sstevel@tonic-gate */ 370*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&termsig); 371*7c478bd9Sstevel@tonic-gate (void) sigaddset(&termsig, SIGHUP); 372*7c478bd9Sstevel@tonic-gate (void) sigaddset(&termsig, SIGTERM); 373*7c478bd9Sstevel@tonic-gate (void) sigaddset(&termsig, SIGINT); 374*7c478bd9Sstevel@tonic-gate (void) sigaddset(&termsig, SIGQUIT); 375*7c478bd9Sstevel@tonic-gate } 376*7c478bd9Sstevel@tonic-gate 377*7c478bd9Sstevel@tonic-gate #pragma init(__libpctx_init) 378*7c478bd9Sstevel@tonic-gate 379*7c478bd9Sstevel@tonic-gate static void 380*7c478bd9Sstevel@tonic-gate pctx_begin_syscalls(pctx_t *pctx) 381*7c478bd9Sstevel@tonic-gate { 382*7c478bd9Sstevel@tonic-gate if (pctx->Pr == NULL) 383*7c478bd9Sstevel@tonic-gate return; 384*7c478bd9Sstevel@tonic-gate if (pctx->sigblocked++ == 0) { 385*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &termsig, &pctx->savedset); 386*7c478bd9Sstevel@tonic-gate (void) Pcreate_agent(pctx->Pr); 387*7c478bd9Sstevel@tonic-gate } 388*7c478bd9Sstevel@tonic-gate } 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate static void 391*7c478bd9Sstevel@tonic-gate pctx_end_syscalls(pctx_t *pctx) 392*7c478bd9Sstevel@tonic-gate { 393*7c478bd9Sstevel@tonic-gate if (pctx->Pr == NULL) 394*7c478bd9Sstevel@tonic-gate return; 395*7c478bd9Sstevel@tonic-gate if (--pctx->sigblocked == 0) { 396*7c478bd9Sstevel@tonic-gate (void) Pdestroy_agent(pctx->Pr); 397*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &pctx->savedset, NULL); 398*7c478bd9Sstevel@tonic-gate } 399*7c478bd9Sstevel@tonic-gate } 400*7c478bd9Sstevel@tonic-gate 401*7c478bd9Sstevel@tonic-gate /* 402*7c478bd9Sstevel@tonic-gate * Iterate over the valid lwpids in the process, invoking the 403*7c478bd9Sstevel@tonic-gate * action function on each one. 404*7c478bd9Sstevel@tonic-gate */ 405*7c478bd9Sstevel@tonic-gate static int 406*7c478bd9Sstevel@tonic-gate pctx_lwpiterate(pctx_t *pctx, int (*action)(pctx_t *, pid_t, id_t, void *)) 407*7c478bd9Sstevel@tonic-gate { 408*7c478bd9Sstevel@tonic-gate const pstatus_t *pstatus; 409*7c478bd9Sstevel@tonic-gate char lstatus[64]; 410*7c478bd9Sstevel@tonic-gate struct stat statb; 411*7c478bd9Sstevel@tonic-gate lwpstatus_t *lwps; 412*7c478bd9Sstevel@tonic-gate prheader_t *prh; 413*7c478bd9Sstevel@tonic-gate int fd, nlwp; 414*7c478bd9Sstevel@tonic-gate int ret = 0; 415*7c478bd9Sstevel@tonic-gate 416*7c478bd9Sstevel@tonic-gate if (action == (int (*)(pctx_t *, pid_t, id_t, void *))default_int) 417*7c478bd9Sstevel@tonic-gate return (0); 418*7c478bd9Sstevel@tonic-gate 419*7c478bd9Sstevel@tonic-gate pstatus = Pstatus(pctx->Pr); 420*7c478bd9Sstevel@tonic-gate if (pstatus->pr_nlwp <= 1) { 421*7c478bd9Sstevel@tonic-gate pctx_begin_syscalls(pctx); 422*7c478bd9Sstevel@tonic-gate ret = action(pctx, pstatus->pr_pid, 1, pctx->uarg); 423*7c478bd9Sstevel@tonic-gate pctx_end_syscalls(pctx); 424*7c478bd9Sstevel@tonic-gate return (ret); 425*7c478bd9Sstevel@tonic-gate } 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate (void) snprintf(lstatus, sizeof (lstatus), 428*7c478bd9Sstevel@tonic-gate "/proc/%d/lstatus", (int)pstatus->pr_pid); 429*7c478bd9Sstevel@tonic-gate 430*7c478bd9Sstevel@tonic-gate if ((fd = open(lstatus, O_RDONLY)) < 0 || 431*7c478bd9Sstevel@tonic-gate fstat(fd, &statb) != 0) { 432*7c478bd9Sstevel@tonic-gate if (fd >= 0) 433*7c478bd9Sstevel@tonic-gate (void) close(fd); 434*7c478bd9Sstevel@tonic-gate return (-1); 435*7c478bd9Sstevel@tonic-gate } 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate prh = malloc(statb.st_size); 438*7c478bd9Sstevel@tonic-gate if (read(fd, prh, statb.st_size) < 439*7c478bd9Sstevel@tonic-gate sizeof (prheader_t) + sizeof (lwpstatus_t)) { 440*7c478bd9Sstevel@tonic-gate (void) close(fd); 441*7c478bd9Sstevel@tonic-gate free(prh); 442*7c478bd9Sstevel@tonic-gate return (-1); 443*7c478bd9Sstevel@tonic-gate } 444*7c478bd9Sstevel@tonic-gate (void) close(fd); 445*7c478bd9Sstevel@tonic-gate 446*7c478bd9Sstevel@tonic-gate /* LINTED pointer cast may result in improper alignment */ 447*7c478bd9Sstevel@tonic-gate lwps = (lwpstatus_t *)(prh + 1); 448*7c478bd9Sstevel@tonic-gate pctx_begin_syscalls(pctx); 449*7c478bd9Sstevel@tonic-gate for (nlwp = prh->pr_nent; nlwp > 0; nlwp--) { 450*7c478bd9Sstevel@tonic-gate if (action(pctx, 451*7c478bd9Sstevel@tonic-gate pstatus->pr_pid, lwps->pr_lwpid, pctx->uarg) != 0) 452*7c478bd9Sstevel@tonic-gate ret = -1; 453*7c478bd9Sstevel@tonic-gate /* LINTED pointer cast may result in improper alignment */ 454*7c478bd9Sstevel@tonic-gate lwps = (lwpstatus_t *)((char *)lwps + prh->pr_entsize); 455*7c478bd9Sstevel@tonic-gate } 456*7c478bd9Sstevel@tonic-gate pctx_end_syscalls(pctx); 457*7c478bd9Sstevel@tonic-gate free(prh); 458*7c478bd9Sstevel@tonic-gate return (ret); 459*7c478bd9Sstevel@tonic-gate } 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate /* 462*7c478bd9Sstevel@tonic-gate * Free any associated state, but leave the process stopped if it 463*7c478bd9Sstevel@tonic-gate * is still under our control. (If it isn't under our control, 464*7c478bd9Sstevel@tonic-gate * it should just run to completion when we do our last close) 465*7c478bd9Sstevel@tonic-gate */ 466*7c478bd9Sstevel@tonic-gate static void 467*7c478bd9Sstevel@tonic-gate pctx_free(pctx_t *pctx) 468*7c478bd9Sstevel@tonic-gate { 469*7c478bd9Sstevel@tonic-gate if (pctx->cpc != NULL && pctx_cpc_callback != NULL) 470*7c478bd9Sstevel@tonic-gate (*pctx_cpc_callback)(pctx->cpc, pctx); 471*7c478bd9Sstevel@tonic-gate if (pctx->Pr) { 472*7c478bd9Sstevel@tonic-gate Pfree(pctx->Pr); 473*7c478bd9Sstevel@tonic-gate pctx->Pr = NULL; 474*7c478bd9Sstevel@tonic-gate } 475*7c478bd9Sstevel@tonic-gate pctx->errfn = pctx_default_errfn; 476*7c478bd9Sstevel@tonic-gate } 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate /* 479*7c478bd9Sstevel@tonic-gate * Completely release the process from our control and discard all our state 480*7c478bd9Sstevel@tonic-gate */ 481*7c478bd9Sstevel@tonic-gate void 482*7c478bd9Sstevel@tonic-gate pctx_release(pctx_t *pctx) 483*7c478bd9Sstevel@tonic-gate { 484*7c478bd9Sstevel@tonic-gate if (pctx->Pr) { 485*7c478bd9Sstevel@tonic-gate Prelease(pctx->Pr, PRELEASE_CLEAR); 486*7c478bd9Sstevel@tonic-gate pctx->Pr = NULL; 487*7c478bd9Sstevel@tonic-gate } 488*7c478bd9Sstevel@tonic-gate pctx_free(pctx); 489*7c478bd9Sstevel@tonic-gate bzero(pctx, sizeof (*pctx)); 490*7c478bd9Sstevel@tonic-gate free(pctx); 491*7c478bd9Sstevel@tonic-gate } 492*7c478bd9Sstevel@tonic-gate 493*7c478bd9Sstevel@tonic-gate static void 494*7c478bd9Sstevel@tonic-gate msincr(struct timeval *tv, uint_t msec) 495*7c478bd9Sstevel@tonic-gate { 496*7c478bd9Sstevel@tonic-gate tv->tv_sec += msec / MILLISEC; 497*7c478bd9Sstevel@tonic-gate tv->tv_usec += (msec % MILLISEC) * MILLISEC; 498*7c478bd9Sstevel@tonic-gate if (tv->tv_usec > MICROSEC) { 499*7c478bd9Sstevel@tonic-gate tv->tv_sec++; 500*7c478bd9Sstevel@tonic-gate tv->tv_usec -= MICROSEC; 501*7c478bd9Sstevel@tonic-gate } 502*7c478bd9Sstevel@tonic-gate } 503*7c478bd9Sstevel@tonic-gate 504*7c478bd9Sstevel@tonic-gate static uint_t 505*7c478bd9Sstevel@tonic-gate msdiff(struct timeval *tva, struct timeval *tvb) 506*7c478bd9Sstevel@tonic-gate { 507*7c478bd9Sstevel@tonic-gate time_t sdiff = tva->tv_sec - tvb->tv_sec; 508*7c478bd9Sstevel@tonic-gate suseconds_t udiff = tva->tv_usec - tvb->tv_usec; 509*7c478bd9Sstevel@tonic-gate 510*7c478bd9Sstevel@tonic-gate if (sdiff < 0) 511*7c478bd9Sstevel@tonic-gate return (0); 512*7c478bd9Sstevel@tonic-gate if (udiff < 0) { 513*7c478bd9Sstevel@tonic-gate udiff += MICROSEC; 514*7c478bd9Sstevel@tonic-gate sdiff--; 515*7c478bd9Sstevel@tonic-gate } 516*7c478bd9Sstevel@tonic-gate if (sdiff < 0) 517*7c478bd9Sstevel@tonic-gate return (0); 518*7c478bd9Sstevel@tonic-gate if (sdiff >= (INT_MAX / MILLISEC)) 519*7c478bd9Sstevel@tonic-gate return ((uint_t)INT_MAX); 520*7c478bd9Sstevel@tonic-gate return ((uint_t)(sdiff * MILLISEC + udiff / MILLISEC)); 521*7c478bd9Sstevel@tonic-gate } 522*7c478bd9Sstevel@tonic-gate 523*7c478bd9Sstevel@tonic-gate int 524*7c478bd9Sstevel@tonic-gate pctx_run( 525*7c478bd9Sstevel@tonic-gate pctx_t *pctx, 526*7c478bd9Sstevel@tonic-gate uint_t msec, 527*7c478bd9Sstevel@tonic-gate uint_t nsamples, 528*7c478bd9Sstevel@tonic-gate int (*tick)(pctx_t *, pid_t, id_t, void *)) 529*7c478bd9Sstevel@tonic-gate { 530*7c478bd9Sstevel@tonic-gate static const char fn[] = "run"; 531*7c478bd9Sstevel@tonic-gate struct timeval tvgoal, tvnow; 532*7c478bd9Sstevel@tonic-gate uint_t mswait = 0; 533*7c478bd9Sstevel@tonic-gate int running = 1; 534*7c478bd9Sstevel@tonic-gate const pstatus_t *pstatus; 535*7c478bd9Sstevel@tonic-gate psinfo_t psinfo; 536*7c478bd9Sstevel@tonic-gate void (*sigsaved)(); 537*7c478bd9Sstevel@tonic-gate id_t lwpid; 538*7c478bd9Sstevel@tonic-gate pid_t pid = Pstatus(pctx->Pr)->pr_pid; 539*7c478bd9Sstevel@tonic-gate int pstate; 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate if (msec == 0) 542*7c478bd9Sstevel@tonic-gate nsamples = 0; 543*7c478bd9Sstevel@tonic-gate if (nsamples == 0) 544*7c478bd9Sstevel@tonic-gate nsamples = UINT_MAX; 545*7c478bd9Sstevel@tonic-gate 546*7c478bd9Sstevel@tonic-gate /* 547*7c478bd9Sstevel@tonic-gate * Casually discard any knowledge of the children we create 548*7c478bd9Sstevel@tonic-gate */ 549*7c478bd9Sstevel@tonic-gate sigsaved = signal(SIGCHLD, SIG_IGN); 550*7c478bd9Sstevel@tonic-gate 551*7c478bd9Sstevel@tonic-gate /* 552*7c478bd9Sstevel@tonic-gate * Since we've just "discovered" this process which might have 553*7c478bd9Sstevel@tonic-gate * been running for weeks, deliver some init_lwp events so 554*7c478bd9Sstevel@tonic-gate * that our caller gets a handle on the process. 555*7c478bd9Sstevel@tonic-gate */ 556*7c478bd9Sstevel@tonic-gate if (pctx_lwpiterate(pctx, pctx->init_lwp) != 0) { 557*7c478bd9Sstevel@tonic-gate if (pctx->verbose) 558*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 559*7c478bd9Sstevel@tonic-gate gettext("%d: lwp discovery failed\n"), (int)pid); 560*7c478bd9Sstevel@tonic-gate goto bailout; 561*7c478bd9Sstevel@tonic-gate } 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate if (msec != 0) { 564*7c478bd9Sstevel@tonic-gate /* 565*7c478bd9Sstevel@tonic-gate * tvgoal represents the time at which the sample 566*7c478bd9Sstevel@tonic-gate * should next be taken. 567*7c478bd9Sstevel@tonic-gate */ 568*7c478bd9Sstevel@tonic-gate (void) gettimeofday(&tvgoal, 0); 569*7c478bd9Sstevel@tonic-gate msincr(&tvgoal, msec); 570*7c478bd9Sstevel@tonic-gate } 571*7c478bd9Sstevel@tonic-gate 572*7c478bd9Sstevel@tonic-gate while (running) { 573*7c478bd9Sstevel@tonic-gate 574*7c478bd9Sstevel@tonic-gate if (Psetrun(pctx->Pr, 0, 0) != 0) { 575*7c478bd9Sstevel@tonic-gate if (pctx->verbose) 576*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 577*7c478bd9Sstevel@tonic-gate gettext("%d: Psetrun\n"), (int)pid); 578*7c478bd9Sstevel@tonic-gate break; 579*7c478bd9Sstevel@tonic-gate } 580*7c478bd9Sstevel@tonic-gate 581*7c478bd9Sstevel@tonic-gate if (msec != 0) { 582*7c478bd9Sstevel@tonic-gate /* 583*7c478bd9Sstevel@tonic-gate * This timing loop attempts to estimate the number 584*7c478bd9Sstevel@tonic-gate * of milliseconds between our "goal" time (when 585*7c478bd9Sstevel@tonic-gate * we should stop the process and run the tick 586*7c478bd9Sstevel@tonic-gate * routine) and the current time. 587*7c478bd9Sstevel@tonic-gate * 588*7c478bd9Sstevel@tonic-gate * If we ever find ourselves running behind i.e. we 589*7c478bd9Sstevel@tonic-gate * missed our goal, then we skip ahead to the next 590*7c478bd9Sstevel@tonic-gate * goal instead. 591*7c478bd9Sstevel@tonic-gate */ 592*7c478bd9Sstevel@tonic-gate do { 593*7c478bd9Sstevel@tonic-gate (void) gettimeofday(&tvnow, 0); 594*7c478bd9Sstevel@tonic-gate if ((mswait = msdiff(&tvgoal, &tvnow)) == 0) { 595*7c478bd9Sstevel@tonic-gate msincr(&tvgoal, msec); 596*7c478bd9Sstevel@tonic-gate /* 597*7c478bd9Sstevel@tonic-gate * Skip ahead to the next goal, unless 598*7c478bd9Sstevel@tonic-gate * there is only one more sample left 599*7c478bd9Sstevel@tonic-gate * to take. 600*7c478bd9Sstevel@tonic-gate */ 601*7c478bd9Sstevel@tonic-gate if (nsamples != 1) 602*7c478bd9Sstevel@tonic-gate nsamples--; 603*7c478bd9Sstevel@tonic-gate } 604*7c478bd9Sstevel@tonic-gate } while (mswait == 0); 605*7c478bd9Sstevel@tonic-gate } 606*7c478bd9Sstevel@tonic-gate 607*7c478bd9Sstevel@tonic-gate (void) Pwait(pctx->Pr, mswait); 608*7c478bd9Sstevel@tonic-gate 609*7c478bd9Sstevel@tonic-gate checkstate: 610*7c478bd9Sstevel@tonic-gate switch (pstate = Pstate(pctx->Pr)) { 611*7c478bd9Sstevel@tonic-gate case PS_RUN: 612*7c478bd9Sstevel@tonic-gate /* 613*7c478bd9Sstevel@tonic-gate * Try again, but wait for up to 5 seconds. 614*7c478bd9Sstevel@tonic-gate */ 615*7c478bd9Sstevel@tonic-gate if (Pstop(pctx->Pr, 5 * MILLISEC) == -1 || 616*7c478bd9Sstevel@tonic-gate (pstate = Pstate(pctx->Pr)) != PS_STOP) { 617*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 618*7c478bd9Sstevel@tonic-gate gettext("%d: won't stop\n"), (int)pid); 619*7c478bd9Sstevel@tonic-gate } 620*7c478bd9Sstevel@tonic-gate break; 621*7c478bd9Sstevel@tonic-gate case PS_STOP: 622*7c478bd9Sstevel@tonic-gate break; 623*7c478bd9Sstevel@tonic-gate case PS_LOST: 624*7c478bd9Sstevel@tonic-gate /* 625*7c478bd9Sstevel@tonic-gate * Lost control - probably execed a setuid/setgid 626*7c478bd9Sstevel@tonic-gate * executable. Try and get control back again, 627*7c478bd9Sstevel@tonic-gate * else bail .. 628*7c478bd9Sstevel@tonic-gate */ 629*7c478bd9Sstevel@tonic-gate (void) Preopen(pctx->Pr); 630*7c478bd9Sstevel@tonic-gate if ((pstate = Pstate(pctx->Pr)) != PS_LOST) 631*7c478bd9Sstevel@tonic-gate goto checkstate; 632*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 633*7c478bd9Sstevel@tonic-gate gettext("%d: execed a program that cannot " 634*7c478bd9Sstevel@tonic-gate "be tracked\n"), (int)pid); 635*7c478bd9Sstevel@tonic-gate running = 0; 636*7c478bd9Sstevel@tonic-gate break; 637*7c478bd9Sstevel@tonic-gate case PS_UNDEAD: 638*7c478bd9Sstevel@tonic-gate case PS_DEAD: 639*7c478bd9Sstevel@tonic-gate if (pctx->verbose) 640*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 641*7c478bd9Sstevel@tonic-gate gettext("%d: process terminated\n"), 642*7c478bd9Sstevel@tonic-gate (int)pid); 643*7c478bd9Sstevel@tonic-gate running = 0; 644*7c478bd9Sstevel@tonic-gate break; 645*7c478bd9Sstevel@tonic-gate default: 646*7c478bd9Sstevel@tonic-gate if (pctx->verbose) 647*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 648*7c478bd9Sstevel@tonic-gate gettext("%d: process state 0x%x?\n"), 649*7c478bd9Sstevel@tonic-gate (int)pid, pstate); 650*7c478bd9Sstevel@tonic-gate break; 651*7c478bd9Sstevel@tonic-gate } 652*7c478bd9Sstevel@tonic-gate 653*7c478bd9Sstevel@tonic-gate if (pstate != PS_STOP) 654*7c478bd9Sstevel@tonic-gate break; 655*7c478bd9Sstevel@tonic-gate 656*7c478bd9Sstevel@tonic-gate pstatus = Pstatus(pctx->Pr); 657*7c478bd9Sstevel@tonic-gate lwpid = pstatus->pr_lwp.pr_lwpid; 658*7c478bd9Sstevel@tonic-gate switch (pstatus->pr_lwp.pr_why) { 659*7c478bd9Sstevel@tonic-gate case PR_REQUESTED: 660*7c478bd9Sstevel@tonic-gate msincr(&tvgoal, msec); 661*7c478bd9Sstevel@tonic-gate if (pstatus->pr_flags & PR_VFORKP) { 662*7c478bd9Sstevel@tonic-gate /* 663*7c478bd9Sstevel@tonic-gate * The process is in a vfork stupor until 664*7c478bd9Sstevel@tonic-gate * its child releases it via an exec. 665*7c478bd9Sstevel@tonic-gate * Don't sample it while it's in this state 666*7c478bd9Sstevel@tonic-gate * - we won't be able to create the agent. 667*7c478bd9Sstevel@tonic-gate */ 668*7c478bd9Sstevel@tonic-gate break; 669*7c478bd9Sstevel@tonic-gate } 670*7c478bd9Sstevel@tonic-gate if (pctx_lwpiterate(pctx, tick) != 0) 671*7c478bd9Sstevel@tonic-gate running = 0; 672*7c478bd9Sstevel@tonic-gate if (--nsamples == 0) 673*7c478bd9Sstevel@tonic-gate running = 0; 674*7c478bd9Sstevel@tonic-gate break; 675*7c478bd9Sstevel@tonic-gate case PR_SYSENTRY: 676*7c478bd9Sstevel@tonic-gate switch (pstatus->pr_lwp.pr_what) { 677*7c478bd9Sstevel@tonic-gate case SYS_lwp_exit: 678*7c478bd9Sstevel@tonic-gate pctx_begin_syscalls(pctx); 679*7c478bd9Sstevel@tonic-gate (void) pctx->fini_lwp(pctx, 680*7c478bd9Sstevel@tonic-gate pid, lwpid, pctx->uarg); 681*7c478bd9Sstevel@tonic-gate (void) pctx->lwp_exit(pctx, 682*7c478bd9Sstevel@tonic-gate pid, lwpid, pctx->uarg); 683*7c478bd9Sstevel@tonic-gate pctx_end_syscalls(pctx); 684*7c478bd9Sstevel@tonic-gate break; 685*7c478bd9Sstevel@tonic-gate case SYS_exit: 686*7c478bd9Sstevel@tonic-gate (void) pctx_lwpiterate(pctx, pctx->fini_lwp); 687*7c478bd9Sstevel@tonic-gate pctx->exit(pctx, pid, lwpid, 688*7c478bd9Sstevel@tonic-gate (int)pstatus->pr_lwp.pr_sysarg[0], 689*7c478bd9Sstevel@tonic-gate pctx->uarg); 690*7c478bd9Sstevel@tonic-gate running = 0; 691*7c478bd9Sstevel@tonic-gate break; 692*7c478bd9Sstevel@tonic-gate case SYS_exec: 693*7c478bd9Sstevel@tonic-gate case SYS_execve: 694*7c478bd9Sstevel@tonic-gate (void) pctx_lwpiterate(pctx, pctx->fini_lwp); 695*7c478bd9Sstevel@tonic-gate break; 696*7c478bd9Sstevel@tonic-gate default: 697*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 698*7c478bd9Sstevel@tonic-gate "warning - pid %d sysentry(%d)\n", 699*7c478bd9Sstevel@tonic-gate (int)pid, pstatus->pr_lwp.pr_what); 700*7c478bd9Sstevel@tonic-gate break; 701*7c478bd9Sstevel@tonic-gate } 702*7c478bd9Sstevel@tonic-gate break; 703*7c478bd9Sstevel@tonic-gate case PR_SYSEXIT: 704*7c478bd9Sstevel@tonic-gate switch (pstatus->pr_lwp.pr_what) { 705*7c478bd9Sstevel@tonic-gate case SYS_exec: 706*7c478bd9Sstevel@tonic-gate case SYS_execve: 707*7c478bd9Sstevel@tonic-gate if (pstatus->pr_lwp.pr_errno) { 708*7c478bd9Sstevel@tonic-gate /* 709*7c478bd9Sstevel@tonic-gate * The exec failed completely. 710*7c478bd9Sstevel@tonic-gate * Reinstate the lwps we fini'd 711*7c478bd9Sstevel@tonic-gate * at exec entrance 712*7c478bd9Sstevel@tonic-gate */ 713*7c478bd9Sstevel@tonic-gate running = pctx_lwpiterate(pctx, 714*7c478bd9Sstevel@tonic-gate pctx->init_lwp) == 0; 715*7c478bd9Sstevel@tonic-gate break; 716*7c478bd9Sstevel@tonic-gate } 717*7c478bd9Sstevel@tonic-gate if (pctx->exec == (pctx_sysc_execfn_t *) 718*7c478bd9Sstevel@tonic-gate default_int) { 719*7c478bd9Sstevel@tonic-gate running = 0; 720*7c478bd9Sstevel@tonic-gate break; 721*7c478bd9Sstevel@tonic-gate } 722*7c478bd9Sstevel@tonic-gate (void) memcpy(&psinfo, 723*7c478bd9Sstevel@tonic-gate Ppsinfo(pctx->Pr), sizeof (psinfo)); 724*7c478bd9Sstevel@tonic-gate proc_unctrl_psinfo(&psinfo); 725*7c478bd9Sstevel@tonic-gate pctx_begin_syscalls(pctx); 726*7c478bd9Sstevel@tonic-gate running = pctx->exec(pctx, pid, 727*7c478bd9Sstevel@tonic-gate lwpid, psinfo.pr_psargs, pctx->uarg) == 0; 728*7c478bd9Sstevel@tonic-gate running = running && pctx->init_lwp(pctx, 729*7c478bd9Sstevel@tonic-gate pid, 1, pctx->uarg) == 0; 730*7c478bd9Sstevel@tonic-gate pctx_end_syscalls(pctx); 731*7c478bd9Sstevel@tonic-gate break; 732*7c478bd9Sstevel@tonic-gate case SYS_lwp_create: 733*7c478bd9Sstevel@tonic-gate if (pstatus->pr_lwp.pr_errno || 734*7c478bd9Sstevel@tonic-gate pstatus->pr_lwp.pr_rval1) 735*7c478bd9Sstevel@tonic-gate break; 736*7c478bd9Sstevel@tonic-gate pctx_begin_syscalls(pctx); 737*7c478bd9Sstevel@tonic-gate running = pctx->init_lwp(pctx, 738*7c478bd9Sstevel@tonic-gate pid, lwpid, pctx->uarg) == 0; 739*7c478bd9Sstevel@tonic-gate running = running && pctx->lwp_create(pctx, 740*7c478bd9Sstevel@tonic-gate pid, lwpid, pctx->uarg) == 0; 741*7c478bd9Sstevel@tonic-gate pctx_end_syscalls(pctx); 742*7c478bd9Sstevel@tonic-gate break; 743*7c478bd9Sstevel@tonic-gate case SYS_forkall: 744*7c478bd9Sstevel@tonic-gate case SYS_vfork: 745*7c478bd9Sstevel@tonic-gate case SYS_fork1: 746*7c478bd9Sstevel@tonic-gate if (pstatus->pr_lwp.pr_errno) 747*7c478bd9Sstevel@tonic-gate break; 748*7c478bd9Sstevel@tonic-gate (void) fflush(NULL); 749*7c478bd9Sstevel@tonic-gate switch (fork1()) { 750*7c478bd9Sstevel@tonic-gate pid_t ppid; 751*7c478bd9Sstevel@tonic-gate int wascreated; 752*7c478bd9Sstevel@tonic-gate pctx_sysc_forkfn_t *forkfn; 753*7c478bd9Sstevel@tonic-gate case 0: 754*7c478bd9Sstevel@tonic-gate ppid = pid; 755*7c478bd9Sstevel@tonic-gate pid = pstatus->pr_lwp.pr_rval1; 756*7c478bd9Sstevel@tonic-gate wascreated = pctx->created; 757*7c478bd9Sstevel@tonic-gate forkfn = pctx->fork; 758*7c478bd9Sstevel@tonic-gate pctx_free(pctx); 759*7c478bd9Sstevel@tonic-gate pctx = pctx_capture(pid, pctx->uarg, 760*7c478bd9Sstevel@tonic-gate pctx->verbose, pctx->errfn); 761*7c478bd9Sstevel@tonic-gate if (pctx != NULL) { 762*7c478bd9Sstevel@tonic-gate if (wascreated) { 763*7c478bd9Sstevel@tonic-gate /* 764*7c478bd9Sstevel@tonic-gate * Set kill on last 765*7c478bd9Sstevel@tonic-gate * close so -all- 766*7c478bd9Sstevel@tonic-gate * children die. 767*7c478bd9Sstevel@tonic-gate */ 768*7c478bd9Sstevel@tonic-gate pctx->created = 1; 769*7c478bd9Sstevel@tonic-gate (void) Psetflags( 770*7c478bd9Sstevel@tonic-gate pctx->Pr, PR_KLC); 771*7c478bd9Sstevel@tonic-gate } 772*7c478bd9Sstevel@tonic-gate (*forkfn)(pctx, ppid, pid, 773*7c478bd9Sstevel@tonic-gate lwpid, pctx->uarg); 774*7c478bd9Sstevel@tonic-gate pctx_release(pctx); 775*7c478bd9Sstevel@tonic-gate } 776*7c478bd9Sstevel@tonic-gate _exit(0); 777*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 778*7c478bd9Sstevel@tonic-gate case -1: 779*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 780*7c478bd9Sstevel@tonic-gate "cannot follow pid %d: %s\n", 781*7c478bd9Sstevel@tonic-gate (int)pstatus->pr_lwp.pr_rval1, 782*7c478bd9Sstevel@tonic-gate strerror(errno)); 783*7c478bd9Sstevel@tonic-gate break; 784*7c478bd9Sstevel@tonic-gate default: 785*7c478bd9Sstevel@tonic-gate break; 786*7c478bd9Sstevel@tonic-gate } 787*7c478bd9Sstevel@tonic-gate break; 788*7c478bd9Sstevel@tonic-gate default: 789*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, gettext( 790*7c478bd9Sstevel@tonic-gate "warning - pid %d sysexit(%d)\n"), 791*7c478bd9Sstevel@tonic-gate (int)pid, pstatus->pr_lwp.pr_what); 792*7c478bd9Sstevel@tonic-gate break; 793*7c478bd9Sstevel@tonic-gate } 794*7c478bd9Sstevel@tonic-gate break; 795*7c478bd9Sstevel@tonic-gate case PR_SIGNALLED: 796*7c478bd9Sstevel@tonic-gate if (pctx->verbose) 797*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 798*7c478bd9Sstevel@tonic-gate gettext("pid %d - signalled\n"), (int)pid); 799*7c478bd9Sstevel@tonic-gate break; 800*7c478bd9Sstevel@tonic-gate case PR_JOBCONTROL: 801*7c478bd9Sstevel@tonic-gate if (pctx->verbose) 802*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 803*7c478bd9Sstevel@tonic-gate gettext("pid %d - job control stop\n"), 804*7c478bd9Sstevel@tonic-gate (int)pid); 805*7c478bd9Sstevel@tonic-gate running = 0; 806*7c478bd9Sstevel@tonic-gate break; 807*7c478bd9Sstevel@tonic-gate case PR_FAULTED: 808*7c478bd9Sstevel@tonic-gate if (pctx->verbose) 809*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 810*7c478bd9Sstevel@tonic-gate gettext("pid %d - faulted\n"), (int)pid); 811*7c478bd9Sstevel@tonic-gate break; 812*7c478bd9Sstevel@tonic-gate case PR_SUSPENDED: 813*7c478bd9Sstevel@tonic-gate if (pctx->verbose) 814*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 815*7c478bd9Sstevel@tonic-gate gettext("pid %d - suspended\n"), (int)pid); 816*7c478bd9Sstevel@tonic-gate break; 817*7c478bd9Sstevel@tonic-gate case PR_CHECKPOINT: 818*7c478bd9Sstevel@tonic-gate if (pctx->verbose) 819*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 820*7c478bd9Sstevel@tonic-gate gettext("pid %d - checkpoint\n"), 821*7c478bd9Sstevel@tonic-gate (int)pid); 822*7c478bd9Sstevel@tonic-gate break; 823*7c478bd9Sstevel@tonic-gate default: 824*7c478bd9Sstevel@tonic-gate if (pctx->verbose) 825*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, 826*7c478bd9Sstevel@tonic-gate gettext("pid %d - reason %d\n"), 827*7c478bd9Sstevel@tonic-gate (int)pid, pstatus->pr_lwp.pr_why); 828*7c478bd9Sstevel@tonic-gate running = 0; 829*7c478bd9Sstevel@tonic-gate break; 830*7c478bd9Sstevel@tonic-gate } 831*7c478bd9Sstevel@tonic-gate } 832*7c478bd9Sstevel@tonic-gate 833*7c478bd9Sstevel@tonic-gate bailout: 834*7c478bd9Sstevel@tonic-gate (void) signal(SIGCHLD, sigsaved); 835*7c478bd9Sstevel@tonic-gate if (!running) 836*7c478bd9Sstevel@tonic-gate return (0); 837*7c478bd9Sstevel@tonic-gate 838*7c478bd9Sstevel@tonic-gate pctx_error(pctx, fn, gettext("lost control of pid %d\n"), (int)pid); 839*7c478bd9Sstevel@tonic-gate pctx_free(pctx); 840*7c478bd9Sstevel@tonic-gate return (-1); 841*7c478bd9Sstevel@tonic-gate } 842*7c478bd9Sstevel@tonic-gate 843*7c478bd9Sstevel@tonic-gate /* 844*7c478bd9Sstevel@tonic-gate * Execute the private 'cpc' system call in the context of the 845*7c478bd9Sstevel@tonic-gate * controlled process. 846*7c478bd9Sstevel@tonic-gate */ 847*7c478bd9Sstevel@tonic-gate int 848*7c478bd9Sstevel@tonic-gate __pctx_cpc(pctx_t *pctx, cpc_t *cpc, 849*7c478bd9Sstevel@tonic-gate int cmd, id_t lwpid, void *data1, void *data2, void *data3, int bufsize) 850*7c478bd9Sstevel@tonic-gate { 851*7c478bd9Sstevel@tonic-gate sysret_t rval; 852*7c478bd9Sstevel@tonic-gate argdes_t argd[5]; 853*7c478bd9Sstevel@tonic-gate argdes_t *adp = &argd[0]; 854*7c478bd9Sstevel@tonic-gate int error; 855*7c478bd9Sstevel@tonic-gate 856*7c478bd9Sstevel@tonic-gate /* 857*7c478bd9Sstevel@tonic-gate * Keep track of the relationship between cpc_t and pctx_t here. 858*7c478bd9Sstevel@tonic-gate * We store the last cpc_t used by libpctx, so that when this pctx is 859*7c478bd9Sstevel@tonic-gate * destroyed, libpctx can notify libcpc. 860*7c478bd9Sstevel@tonic-gate */ 861*7c478bd9Sstevel@tonic-gate if (pctx->cpc != NULL && pctx->cpc != cpc && pctx_cpc_callback != NULL) 862*7c478bd9Sstevel@tonic-gate (*pctx_cpc_callback)(pctx->cpc, pctx); 863*7c478bd9Sstevel@tonic-gate pctx->cpc = cpc; 864*7c478bd9Sstevel@tonic-gate 865*7c478bd9Sstevel@tonic-gate /* 866*7c478bd9Sstevel@tonic-gate * cmd and lwpid are passed in by value no matter what the command is. 867*7c478bd9Sstevel@tonic-gate */ 868*7c478bd9Sstevel@tonic-gate adp->arg_value = cmd; 869*7c478bd9Sstevel@tonic-gate adp->arg_object = NULL; 870*7c478bd9Sstevel@tonic-gate adp->arg_type = AT_BYVAL; 871*7c478bd9Sstevel@tonic-gate adp->arg_inout = AI_INPUT; 872*7c478bd9Sstevel@tonic-gate adp->arg_size = 0; 873*7c478bd9Sstevel@tonic-gate adp++; 874*7c478bd9Sstevel@tonic-gate 875*7c478bd9Sstevel@tonic-gate adp->arg_value = lwpid; 876*7c478bd9Sstevel@tonic-gate adp->arg_object = NULL; 877*7c478bd9Sstevel@tonic-gate adp->arg_type = AT_BYVAL; 878*7c478bd9Sstevel@tonic-gate adp->arg_inout = AI_INPUT; 879*7c478bd9Sstevel@tonic-gate adp->arg_size = 0; 880*7c478bd9Sstevel@tonic-gate adp++; 881*7c478bd9Sstevel@tonic-gate 882*7c478bd9Sstevel@tonic-gate switch (cmd) { 883*7c478bd9Sstevel@tonic-gate case CPC_BIND: 884*7c478bd9Sstevel@tonic-gate adp->arg_value = 0; 885*7c478bd9Sstevel@tonic-gate adp->arg_object = data1; 886*7c478bd9Sstevel@tonic-gate adp->arg_type = AT_BYREF; 887*7c478bd9Sstevel@tonic-gate adp->arg_inout = AI_INPUT; 888*7c478bd9Sstevel@tonic-gate adp->arg_size = (size_t)data2; 889*7c478bd9Sstevel@tonic-gate adp++; 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate adp->arg_value = (size_t)data2; 892*7c478bd9Sstevel@tonic-gate adp->arg_object = NULL; 893*7c478bd9Sstevel@tonic-gate adp->arg_type = AT_BYVAL; 894*7c478bd9Sstevel@tonic-gate adp->arg_inout = AI_INPUT; 895*7c478bd9Sstevel@tonic-gate adp->arg_size = 0; 896*7c478bd9Sstevel@tonic-gate adp++; 897*7c478bd9Sstevel@tonic-gate 898*7c478bd9Sstevel@tonic-gate adp->arg_value = 0; 899*7c478bd9Sstevel@tonic-gate adp->arg_object = data3; 900*7c478bd9Sstevel@tonic-gate adp->arg_type = AT_BYREF; 901*7c478bd9Sstevel@tonic-gate adp->arg_inout = AI_INOUT; 902*7c478bd9Sstevel@tonic-gate adp->arg_size = sizeof (int); 903*7c478bd9Sstevel@tonic-gate 904*7c478bd9Sstevel@tonic-gate break; 905*7c478bd9Sstevel@tonic-gate case CPC_SAMPLE: 906*7c478bd9Sstevel@tonic-gate adp->arg_value = 0; 907*7c478bd9Sstevel@tonic-gate adp->arg_object = data1; 908*7c478bd9Sstevel@tonic-gate adp->arg_type = AT_BYREF; 909*7c478bd9Sstevel@tonic-gate adp->arg_inout = AI_OUTPUT; 910*7c478bd9Sstevel@tonic-gate adp->arg_size = bufsize; 911*7c478bd9Sstevel@tonic-gate adp++; 912*7c478bd9Sstevel@tonic-gate 913*7c478bd9Sstevel@tonic-gate adp->arg_value = 0; 914*7c478bd9Sstevel@tonic-gate adp->arg_object = data2; 915*7c478bd9Sstevel@tonic-gate adp->arg_type = AT_BYREF; 916*7c478bd9Sstevel@tonic-gate adp->arg_inout = AI_OUTPUT; 917*7c478bd9Sstevel@tonic-gate adp->arg_size = sizeof (hrtime_t); 918*7c478bd9Sstevel@tonic-gate adp++; 919*7c478bd9Sstevel@tonic-gate 920*7c478bd9Sstevel@tonic-gate adp->arg_value = 0; 921*7c478bd9Sstevel@tonic-gate adp->arg_object = data3; 922*7c478bd9Sstevel@tonic-gate adp->arg_type = AT_BYREF; 923*7c478bd9Sstevel@tonic-gate adp->arg_inout = AI_OUTPUT; 924*7c478bd9Sstevel@tonic-gate adp->arg_size = sizeof (uint64_t); 925*7c478bd9Sstevel@tonic-gate 926*7c478bd9Sstevel@tonic-gate break; 927*7c478bd9Sstevel@tonic-gate default: 928*7c478bd9Sstevel@tonic-gate adp->arg_value = 0; 929*7c478bd9Sstevel@tonic-gate adp->arg_object = 0; 930*7c478bd9Sstevel@tonic-gate adp->arg_type = AT_BYVAL; 931*7c478bd9Sstevel@tonic-gate adp->arg_inout = AI_INPUT; 932*7c478bd9Sstevel@tonic-gate adp->arg_size = 0; 933*7c478bd9Sstevel@tonic-gate adp++; 934*7c478bd9Sstevel@tonic-gate 935*7c478bd9Sstevel@tonic-gate adp->arg_value = 0; 936*7c478bd9Sstevel@tonic-gate adp->arg_object = 0; 937*7c478bd9Sstevel@tonic-gate adp->arg_type = AT_BYVAL; 938*7c478bd9Sstevel@tonic-gate adp->arg_inout = AI_INPUT; 939*7c478bd9Sstevel@tonic-gate adp->arg_size = 0; 940*7c478bd9Sstevel@tonic-gate adp++; 941*7c478bd9Sstevel@tonic-gate 942*7c478bd9Sstevel@tonic-gate adp->arg_value = 0; 943*7c478bd9Sstevel@tonic-gate adp->arg_object = 0; 944*7c478bd9Sstevel@tonic-gate adp->arg_type = AT_BYVAL; 945*7c478bd9Sstevel@tonic-gate adp->arg_inout = AI_INPUT; 946*7c478bd9Sstevel@tonic-gate adp->arg_size = 0; 947*7c478bd9Sstevel@tonic-gate 948*7c478bd9Sstevel@tonic-gate break; 949*7c478bd9Sstevel@tonic-gate } 950*7c478bd9Sstevel@tonic-gate 951*7c478bd9Sstevel@tonic-gate error = Psyscall(pctx->Pr, &rval, SYS_cpc, 5, &argd[0]); 952*7c478bd9Sstevel@tonic-gate 953*7c478bd9Sstevel@tonic-gate if (error) { 954*7c478bd9Sstevel@tonic-gate errno = error > 0 ? error : ENOSYS; 955*7c478bd9Sstevel@tonic-gate return (-1); 956*7c478bd9Sstevel@tonic-gate } 957*7c478bd9Sstevel@tonic-gate return (rval.sys_rval1); 958*7c478bd9Sstevel@tonic-gate } 959*7c478bd9Sstevel@tonic-gate 960*7c478bd9Sstevel@tonic-gate /* 961*7c478bd9Sstevel@tonic-gate * libcpc-private hook used to register a callback. The callback is used to 962*7c478bd9Sstevel@tonic-gate * notify libcpc when a pctx handle is invalidated. 963*7c478bd9Sstevel@tonic-gate */ 964*7c478bd9Sstevel@tonic-gate void 965*7c478bd9Sstevel@tonic-gate __pctx_cpc_register_callback(void (*arg)(struct __cpc *, struct __pctx *)) 966*7c478bd9Sstevel@tonic-gate { 967*7c478bd9Sstevel@tonic-gate pctx_cpc_callback = arg; 968*7c478bd9Sstevel@tonic-gate } 969