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