8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libpctx / common / libpctx.c
blobec10bbcb6923326c78c119e21269ee2c6d8571f2
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * This file contains a set of generic routines for periodically
29 * sampling the state of another process, or tree of processes.
31 * It is built upon the infrastructure provided by libproc.
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>
51 #include "libpctx.h"
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;
72 static void (*pctx_cpc_callback)(cpc_t *cpc, struct __pctx *pctx);
74 static void
75 pctx_default_errfn(const char *fn, const char *fmt, va_list ap)
77 (void) fprintf(stderr, "libpctx: pctx_%s: ", fn);
78 (void) vfprintf(stderr, fmt, ap);
81 /*PRINTFLIKE3*/
82 static void
83 pctx_error(pctx_t *pctx, const char *fn, const char *fmt, ...)
85 va_list ap;
87 va_start(ap, fmt);
88 pctx->errfn(fn, fmt, ap);
89 va_end(ap);
93 * Create a new process and bind the user args for it
95 pctx_t *
96 pctx_create(
97 const char *filename,
98 char *const *argv,
99 void *arg,
100 int verbose,
101 pctx_errfn_t *errfn)
103 static const char fn[] = "create";
104 int err;
105 pctx_t *pctx;
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;
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;
140 free(pctx);
141 return (NULL);
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);
152 * Set kill-on-last-close so the controlled process
153 * dies if we die.
155 pctx->created = 1;
156 (void) Psetflags(pctx->Pr, PR_KLC);
157 (void) pctx_set_events(pctx, PCTX_NULL_EVENT);
159 return (pctx);
163 * Capture an existing process and bind the user args for it
165 pctx_t *
166 pctx_capture(pid_t pid, void *arg, int verbose, pctx_errfn_t *errfn)
168 static const char fn[] = "capture";
169 int err;
170 pctx_t *pctx;
172 pctx = calloc(1, sizeof (*pctx));
173 pctx->uarg = arg;
174 pctx->verbose = verbose;
175 pctx->errfn = errfn ? errfn : pctx_default_errfn;
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;
213 free(pctx);
214 return (NULL);
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);
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.
231 pctx->created = 0;
232 (void) Psetflags(pctx->Pr, PR_RLC);
233 (void) pctx_set_events(pctx, PCTX_NULL_EVENT);
235 return (pctx);
238 /*ARGSUSED*/
239 static void
240 default_void(pctx_t *pctx)
243 /*ARGSUSED*/
244 static int
245 default_int(pctx_t *pctx)
247 return (0);
251 pctx_set_events(pctx_t *pctx, ...)
253 static const char fn[] = "set_events";
254 va_list pvar;
255 int error = 0;
256 pctx_event_t event;
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;
297 } while (event != PCTX_NULL_EVENT && error == 0);
298 va_end(pvar);
300 if (error != 0)
301 return (error);
303 if (pctx->exec == NULL)
304 pctx->exec = (pctx_sysc_execfn_t *)default_int;
305 if (pctx->fork == NULL)
306 pctx->fork = (pctx_sysc_forkfn_t *)default_void;
307 if (pctx->exit == NULL)
308 pctx->exit = (pctx_sysc_exitfn_t *)default_void;
309 if (pctx->lwp_create == NULL)
310 pctx->lwp_create = (pctx_sysc_lwp_createfn_t *)default_int;
311 if (pctx->init_lwp == NULL)
312 pctx->init_lwp = (pctx_init_lwpfn_t *)default_int;
313 if (pctx->fini_lwp == NULL)
314 pctx->fini_lwp = (pctx_fini_lwpfn_t *)default_int;
315 if (pctx->lwp_exit == NULL)
316 pctx->lwp_exit = (pctx_sysc_lwp_exitfn_t *)default_int;
318 if (pctx->fork != (pctx_sysc_forkfn_t *)default_void) {
319 (void) Psysexit(pctx->Pr, SYS_vfork, 1);
320 (void) Psysexit(pctx->Pr, SYS_forksys, 1);
321 if (Psetflags(pctx->Pr, PR_FORK) == -1)
322 error = -1;
323 } else {
324 (void) Psysexit(pctx->Pr, SYS_vfork, 0);
325 (void) Psysexit(pctx->Pr, SYS_forksys, 0);
326 if (Punsetflags(pctx->Pr, PR_FORK) == -1)
327 error = -1;
331 * exec causes termination of all but the exec-ing lwp,
332 * and resets the lwpid to one in the new address space.
334 if (pctx->exec != (pctx_sysc_execfn_t *)default_int ||
335 pctx->fini_lwp != (pctx_fini_lwpfn_t *)default_int ||
336 pctx->init_lwp != (pctx_init_lwpfn_t *)default_int) {
337 (void) Psysexit(pctx->Pr, SYS_execve, 1);
338 (void) Psysentry(pctx->Pr, SYS_execve, 1);
339 } else {
340 (void) Psysexit(pctx->Pr, SYS_execve, 0);
341 (void) Psysentry(pctx->Pr, SYS_execve, 0);
344 (void) Psysexit(pctx->Pr, SYS_lwp_create,
345 pctx->lwp_create != (pctx_sysc_lwp_createfn_t *)default_int ||
346 pctx->init_lwp != (pctx_init_lwpfn_t *)default_int);
348 (void) Psysentry(pctx->Pr, SYS_lwp_exit,
349 pctx->lwp_exit != (pctx_sysc_lwp_exitfn_t *)default_int ||
350 pctx->fini_lwp != (pctx_fini_lwpfn_t *)default_int);
352 return (0);
355 static sigset_t termsig;
357 static void
358 __libpctx_init(void)
361 * Initialize the signal set used to shield ourselves from
362 * death-by-terminal-signal while the agent lwp is running.
364 (void) sigemptyset(&termsig);
365 (void) sigaddset(&termsig, SIGHUP);
366 (void) sigaddset(&termsig, SIGTERM);
367 (void) sigaddset(&termsig, SIGINT);
368 (void) sigaddset(&termsig, SIGQUIT);
371 #pragma init(__libpctx_init)
373 static void
374 pctx_begin_syscalls(pctx_t *pctx)
376 if (pctx->Pr == NULL)
377 return;
378 if (pctx->sigblocked++ == 0) {
379 (void) sigprocmask(SIG_BLOCK, &termsig, &pctx->savedset);
380 (void) Pcreate_agent(pctx->Pr);
384 static void
385 pctx_end_syscalls(pctx_t *pctx)
387 if (pctx->Pr == NULL)
388 return;
389 if (--pctx->sigblocked == 0) {
390 (void) Pdestroy_agent(pctx->Pr);
391 (void) sigprocmask(SIG_SETMASK, &pctx->savedset, NULL);
396 * Iterate over the valid lwpids in the process, invoking the
397 * action function on each one.
399 static int
400 pctx_lwpiterate(pctx_t *pctx, int (*action)(pctx_t *, pid_t, id_t, void *))
402 const pstatus_t *pstatus;
403 char lstatus[64];
404 struct stat statb;
405 lwpstatus_t *lwps;
406 prheader_t *prh;
407 int fd, nlwp;
408 int ret = 0;
410 if (action == (int (*)(pctx_t *, pid_t, id_t, void *))default_int)
411 return (0);
413 pstatus = Pstatus(pctx->Pr);
414 if (pstatus->pr_nlwp <= 1) {
415 pctx_begin_syscalls(pctx);
416 ret = action(pctx, pstatus->pr_pid, 1, pctx->uarg);
417 pctx_end_syscalls(pctx);
418 return (ret);
421 (void) snprintf(lstatus, sizeof (lstatus),
422 "/proc/%d/lstatus", (int)pstatus->pr_pid);
424 if ((fd = open(lstatus, O_RDONLY)) < 0 ||
425 fstat(fd, &statb) != 0) {
426 if (fd >= 0)
427 (void) close(fd);
428 return (-1);
431 prh = malloc(statb.st_size);
432 if (read(fd, prh, statb.st_size) <
433 sizeof (prheader_t) + sizeof (lwpstatus_t)) {
434 (void) close(fd);
435 free(prh);
436 return (-1);
438 (void) close(fd);
440 /* LINTED pointer cast may result in improper alignment */
441 lwps = (lwpstatus_t *)(prh + 1);
442 pctx_begin_syscalls(pctx);
443 for (nlwp = prh->pr_nent; nlwp > 0; nlwp--) {
444 if (action(pctx,
445 pstatus->pr_pid, lwps->pr_lwpid, pctx->uarg) != 0)
446 ret = -1;
447 /* LINTED pointer cast may result in improper alignment */
448 lwps = (lwpstatus_t *)((char *)lwps + prh->pr_entsize);
450 pctx_end_syscalls(pctx);
451 free(prh);
452 return (ret);
456 * Free any associated state, but leave the process stopped if it
457 * is still under our control. (If it isn't under our control,
458 * it should just run to completion when we do our last close)
460 static void
461 pctx_free(pctx_t *pctx)
463 if (pctx->cpc != NULL && pctx_cpc_callback != NULL)
464 (*pctx_cpc_callback)(pctx->cpc, pctx);
465 if (pctx->Pr) {
466 Pfree(pctx->Pr);
467 pctx->Pr = NULL;
469 pctx->errfn = pctx_default_errfn;
473 * Completely release the process from our control and discard all our state
475 void
476 pctx_release(pctx_t *pctx)
478 if (pctx->Pr) {
479 Prelease(pctx->Pr, PRELEASE_CLEAR);
480 pctx->Pr = NULL;
483 pctx_free(pctx);
484 bzero(pctx, sizeof (*pctx));
485 free(pctx);
488 static void
489 msincr(struct timeval *tv, uint_t msec)
491 tv->tv_sec += msec / MILLISEC;
492 tv->tv_usec += (msec % MILLISEC) * MILLISEC;
493 if (tv->tv_usec > MICROSEC) {
494 tv->tv_sec++;
495 tv->tv_usec -= MICROSEC;
499 static uint_t
500 msdiff(struct timeval *tva, struct timeval *tvb)
502 time_t sdiff = tva->tv_sec - tvb->tv_sec;
503 suseconds_t udiff = tva->tv_usec - tvb->tv_usec;
505 if (sdiff < 0)
506 return (0);
507 if (udiff < 0) {
508 udiff += MICROSEC;
509 sdiff--;
511 if (sdiff < 0)
512 return (0);
513 if (sdiff >= (INT_MAX / MILLISEC))
514 return ((uint_t)INT_MAX);
515 return ((uint_t)(sdiff * MILLISEC + udiff / MILLISEC));
519 pctx_run(
520 pctx_t *pctx,
521 uint_t msec,
522 uint_t nsamples,
523 int (*tick)(pctx_t *, pid_t, id_t, void *))
525 static const char fn[] = "run";
526 struct timeval tvgoal, tvnow;
527 uint_t mswait = 0;
528 int running = 1;
529 const pstatus_t *pstatus;
530 psinfo_t psinfo;
531 void (*sigsaved)();
532 id_t lwpid;
533 pid_t pid = Pstatus(pctx->Pr)->pr_pid;
534 int pstate;
536 if (msec == 0)
537 nsamples = 0;
538 if (nsamples == 0)
539 nsamples = UINT_MAX;
542 * Casually discard any knowledge of the children we create
544 sigsaved = signal(SIGCHLD, SIG_IGN);
547 * Since we've just "discovered" this process which might have
548 * been running for weeks, deliver some init_lwp events so
549 * that our caller gets a handle on the process.
551 if (pctx_lwpiterate(pctx, pctx->init_lwp) != 0) {
552 if (pctx->verbose)
553 pctx_error(pctx, fn,
554 gettext("%d: lwp discovery failed\n"), (int)pid);
555 goto bailout;
558 if (msec != 0) {
560 * tvgoal represents the time at which the sample
561 * should next be taken.
563 (void) gettimeofday(&tvgoal, 0);
564 msincr(&tvgoal, msec);
568 * The event handling loop continues while running is 1.
569 * running becomes 0 when either the controlled process has
570 * exited successfully or the number of time samples has expired.
571 * Otherwise, if an error has occurred, running becomes -1.
573 while (running == 1 && !pctx->terminate) {
575 if (Psetrun(pctx->Pr, 0, 0) != 0) {
576 if (pctx->verbose)
577 pctx_error(pctx, fn,
578 gettext("%d: Psetrun\n"), (int)pid);
579 break;
582 if (msec != 0) {
584 * This timing loop attempts to estimate the number
585 * of milliseconds between our "goal" time (when
586 * we should stop the process and run the tick
587 * routine) and the current time.
589 * If we ever find ourselves running behind i.e. we
590 * missed our goal, then we skip ahead to the next
591 * goal instead.
593 do {
594 (void) gettimeofday(&tvnow, 0);
595 if ((mswait = msdiff(&tvgoal, &tvnow)) == 0) {
596 msincr(&tvgoal, msec);
598 * Skip ahead to the next goal, unless
599 * there is only one more sample left
600 * to take.
602 if (nsamples != 1)
603 nsamples--;
605 } while (mswait == 0 && !pctx->terminate);
608 if (pctx->terminate)
609 goto bailout;
610 else
611 (void) Pwait(pctx->Pr, mswait);
613 checkstate:
614 switch (pstate = Pstate(pctx->Pr)) {
615 case PS_RUN:
617 * Try again, but wait for up to 5 seconds.
619 if (Pstop(pctx->Pr, 5 * MILLISEC) == -1 ||
620 (pstate = Pstate(pctx->Pr)) != PS_STOP) {
621 pctx_error(pctx, fn,
622 gettext("%d: won't stop\n"), (int)pid);
624 break;
625 case PS_STOP:
626 break;
627 case PS_LOST:
629 * Lost control - probably execed a setuid/setgid
630 * executable. Try and get control back again,
631 * else bail ..
633 (void) Preopen(pctx->Pr);
634 if ((pstate = Pstate(pctx->Pr)) != PS_LOST)
635 goto checkstate;
636 pctx_error(pctx, fn,
637 gettext("%d: execed a program that cannot "
638 "be tracked\n"), (int)pid);
639 running = -1;
640 break;
641 case PS_UNDEAD:
642 case PS_DEAD:
643 if (pctx->verbose)
644 pctx_error(pctx, fn,
645 gettext("%d: process terminated\n"),
646 (int)pid);
647 running = -1;
648 break;
649 default:
650 if (pctx->verbose)
651 pctx_error(pctx, fn,
652 gettext("%d: process state 0x%x?\n"),
653 (int)pid, pstate);
654 break;
657 if (pstate != PS_STOP)
658 break;
660 pstatus = Pstatus(pctx->Pr);
661 lwpid = pstatus->pr_lwp.pr_lwpid;
662 switch (pstatus->pr_lwp.pr_why) {
663 case PR_REQUESTED:
664 msincr(&tvgoal, msec);
665 if (pstatus->pr_flags & PR_VFORKP) {
667 * The process is in a vfork stupor until
668 * its child releases it via an exec.
669 * Don't sample it while it's in this state
670 * - we won't be able to create the agent.
672 break;
674 if (pctx_lwpiterate(pctx, tick) != 0)
675 running = -1;
676 if (running == 1 && --nsamples == 0)
677 running = 0;
678 break;
679 case PR_SYSENTRY:
680 switch (pstatus->pr_lwp.pr_what) {
681 case SYS_lwp_exit:
682 pctx_begin_syscalls(pctx);
683 (void) pctx->fini_lwp(pctx,
684 pid, lwpid, pctx->uarg);
685 (void) pctx->lwp_exit(pctx,
686 pid, lwpid, pctx->uarg);
687 pctx_end_syscalls(pctx);
688 break;
689 case SYS_exit:
690 if (pctx_lwpiterate(pctx, pctx->fini_lwp)
691 != 0)
692 running = -1;
693 pctx->exit(pctx, pid, lwpid,
694 (int)pstatus->pr_lwp.pr_sysarg[0],
695 pctx->uarg);
696 if (running == 1)
697 running = 0;
698 break;
699 case SYS_execve:
700 (void) pctx_lwpiterate(pctx, pctx->fini_lwp);
701 break;
702 default:
703 pctx_error(pctx, fn,
704 "warning - pid %d sysentry(%d)\n",
705 (int)pid, pstatus->pr_lwp.pr_what);
706 break;
708 break;
709 case PR_SYSEXIT:
710 switch (pstatus->pr_lwp.pr_what) {
711 case SYS_execve:
712 if (pstatus->pr_lwp.pr_errno) {
714 * The exec failed completely.
715 * Reinstate the lwps we fini'd
716 * at exec entrance
718 if (pctx_lwpiterate(pctx,
719 pctx->init_lwp) == 0)
720 running = 1;
721 else
722 running = -1;
723 break;
725 if (pctx->exec == (pctx_sysc_execfn_t *)
726 default_int) {
727 running = 0;
728 break;
730 (void) memcpy(&psinfo,
731 Ppsinfo(pctx->Pr), sizeof (psinfo));
732 proc_unctrl_psinfo(&psinfo);
733 pctx_begin_syscalls(pctx);
734 if (pctx->exec(pctx, pid, lwpid,
735 psinfo.pr_psargs, pctx->uarg) != 0)
736 running = -1;
737 if (running == 1 && pctx->init_lwp(pctx,
738 pid, 1, pctx->uarg) != 0)
739 running = -1;
740 pctx_end_syscalls(pctx);
741 break;
742 case SYS_lwp_create:
743 if (pstatus->pr_lwp.pr_errno ||
744 pstatus->pr_lwp.pr_rval1)
745 break;
746 pctx_begin_syscalls(pctx);
747 if (pctx->init_lwp(pctx, pid, lwpid,
748 pctx->uarg) != 0)
749 running = -1;
750 if (running == 1 && pctx->lwp_create(pctx,
751 pid, lwpid, pctx->uarg) != 0)
752 running = -1;
753 pctx_end_syscalls(pctx);
754 break;
755 case SYS_vfork:
756 case SYS_forksys:
757 if (pstatus->pr_lwp.pr_errno)
758 break;
759 (void) fflush(NULL);
760 switch (fork1()) {
761 pid_t ppid;
762 int wascreated;
763 pctx_sysc_forkfn_t *forkfn;
764 case 0:
765 ppid = pid;
766 pid = pstatus->pr_lwp.pr_rval1;
767 wascreated = pctx->created;
768 forkfn = pctx->fork;
769 pctx_free(pctx);
770 pctx = pctx_capture(pid, pctx->uarg,
771 pctx->verbose, pctx->errfn);
772 if (pctx != NULL) {
773 if (wascreated) {
775 * Set kill on last
776 * close so -all-
777 * children die.
779 pctx->created = 1;
780 (void) Psetflags(
781 pctx->Pr, PR_KLC);
783 (*forkfn)(pctx, ppid, pid,
784 lwpid, pctx->uarg);
785 pctx_release(pctx);
786 _exit(0);
787 } else {
788 _exit(1);
790 /*NOTREACHED*/
791 case -1:
792 pctx_error(pctx, fn,
793 "cannot follow pid %d: %s\n",
794 (int)pstatus->pr_lwp.pr_rval1,
795 strerror(errno));
796 break;
797 default:
798 break;
800 break;
801 default:
802 pctx_error(pctx, fn, gettext(
803 "warning - pid %d sysexit(%d)\n"),
804 (int)pid, pstatus->pr_lwp.pr_what);
805 break;
807 break;
808 case PR_SIGNALLED:
809 if (pctx->verbose)
810 pctx_error(pctx, fn,
811 gettext("pid %d - signalled\n"), (int)pid);
812 break;
813 case PR_JOBCONTROL:
814 if (pctx->verbose)
815 pctx_error(pctx, fn,
816 gettext("pid %d - job control stop\n"),
817 (int)pid);
818 running = -1;
819 break;
820 case PR_FAULTED:
821 if (pctx->verbose)
822 pctx_error(pctx, fn,
823 gettext("pid %d - faulted\n"), (int)pid);
824 break;
825 case PR_SUSPENDED:
826 if (pctx->verbose)
827 pctx_error(pctx, fn,
828 gettext("pid %d - suspended\n"), (int)pid);
829 break;
830 case PR_CHECKPOINT:
831 if (pctx->verbose)
832 pctx_error(pctx, fn,
833 gettext("pid %d - checkpoint\n"),
834 (int)pid);
835 break;
836 default:
837 if (pctx->verbose)
838 pctx_error(pctx, fn,
839 gettext("pid %d - reason %d\n"),
840 (int)pid, pstatus->pr_lwp.pr_why);
841 running = -1;
842 break;
846 bailout:
847 (void) signal(SIGCHLD, sigsaved);
849 if (pctx->terminate)
850 return (0);
852 switch (running) {
853 case 0:
854 return (0);
855 case -1:
856 return (-1);
857 default:
858 pctx_error(pctx, fn, gettext("lost control of pid %d\n"),
859 (int)pid);
860 pctx_free(pctx);
861 return (-1);
866 * Execute the private 'cpc' system call in the context of the
867 * controlled process.
870 __pctx_cpc(pctx_t *pctx, cpc_t *cpc,
871 int cmd, id_t lwpid, void *data1, void *data2, void *data3, int bufsize)
873 sysret_t rval;
874 argdes_t argd[5];
875 argdes_t *adp = &argd[0];
876 int error;
879 * Keep track of the relationship between cpc_t and pctx_t here.
880 * We store the last cpc_t used by libpctx, so that when this pctx is
881 * destroyed, libpctx can notify libcpc.
884 if (pctx->cpc != NULL && pctx->cpc != cpc && pctx_cpc_callback != NULL)
885 (*pctx_cpc_callback)(pctx->cpc, pctx);
886 pctx->cpc = cpc;
889 * cmd and lwpid are passed in by value no matter what the command is.
891 adp->arg_value = cmd;
892 adp->arg_object = NULL;
893 adp->arg_type = AT_BYVAL;
894 adp->arg_inout = AI_INPUT;
895 adp->arg_size = 0;
896 adp++;
898 adp->arg_value = lwpid;
899 adp->arg_object = NULL;
900 adp->arg_type = AT_BYVAL;
901 adp->arg_inout = AI_INPUT;
902 adp->arg_size = 0;
903 adp++;
905 switch (cmd) {
906 case CPC_BIND:
907 adp->arg_value = 0;
908 adp->arg_object = data1;
909 adp->arg_type = AT_BYREF;
910 adp->arg_inout = AI_INPUT;
911 adp->arg_size = (size_t)data2;
912 adp++;
914 adp->arg_value = (size_t)data2;
915 adp->arg_object = NULL;
916 adp->arg_type = AT_BYVAL;
917 adp->arg_inout = AI_INPUT;
918 adp->arg_size = 0;
919 adp++;
921 adp->arg_value = 0;
922 adp->arg_object = data3;
923 adp->arg_type = AT_BYREF;
924 adp->arg_inout = AI_INOUT;
925 adp->arg_size = sizeof (int);
927 break;
928 case CPC_SAMPLE:
929 adp->arg_value = 0;
930 adp->arg_object = data1;
931 adp->arg_type = AT_BYREF;
932 adp->arg_inout = AI_OUTPUT;
933 adp->arg_size = bufsize;
934 adp++;
936 adp->arg_value = 0;
937 adp->arg_object = data2;
938 adp->arg_type = AT_BYREF;
939 adp->arg_inout = AI_OUTPUT;
940 adp->arg_size = sizeof (hrtime_t);
941 adp++;
943 adp->arg_value = 0;
944 adp->arg_object = data3;
945 adp->arg_type = AT_BYREF;
946 adp->arg_inout = AI_OUTPUT;
947 adp->arg_size = sizeof (uint64_t);
949 break;
950 default:
951 adp->arg_value = 0;
952 adp->arg_object = 0;
953 adp->arg_type = AT_BYVAL;
954 adp->arg_inout = AI_INPUT;
955 adp->arg_size = 0;
956 adp++;
958 adp->arg_value = 0;
959 adp->arg_object = 0;
960 adp->arg_type = AT_BYVAL;
961 adp->arg_inout = AI_INPUT;
962 adp->arg_size = 0;
963 adp++;
965 adp->arg_value = 0;
966 adp->arg_object = 0;
967 adp->arg_type = AT_BYVAL;
968 adp->arg_inout = AI_INPUT;
969 adp->arg_size = 0;
971 break;
974 error = Psyscall(pctx->Pr, &rval, SYS_cpc, 5, &argd[0]);
976 if (error) {
977 errno = error > 0 ? error : ENOSYS;
978 return (-1);
980 return (rval.sys_rval1);
984 * libcpc-private hook used to register a callback. The callback is used to
985 * notify libcpc when a pctx handle is invalidated.
987 void
988 __pctx_cpc_register_callback(void (*arg)(struct __cpc *, struct __pctx *))
990 pctx_cpc_callback = arg;
994 * Tell pctx_run to bail out immediately
996 void
997 pctx_terminate(struct __pctx *pctx)
999 pctx->terminate = 1;