Unleashed v1.4
[unleashed.git] / usr / src / cmd / truss / main.c
blobce219b747f784a2b48374d385e3d5098f921eab7
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 (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2015, Joyent, Inc.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29 #include <stdio.h>
30 #include <stdio_ext.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <ctype.h>
35 #include <string.h>
36 #include <memory.h>
37 #include <signal.h>
38 #include <wait.h>
39 #include <limits.h>
40 #include <errno.h>
41 #include <sys/types.h>
42 #include <sys/time.h>
43 #include <sys/times.h>
44 #include <sys/fstyp.h>
45 #include <sys/fsid.h>
46 #include <sys/stat.h>
47 #include <sys/mman.h>
48 #include <sys/resource.h>
49 #include <libproc.h>
50 #include <priv.h>
51 #include "ramdata.h"
52 #include "proto.h"
53 #include "htbl.h"
56 * The user can trace individual threads by using the 'pid/1,3-6,8-' syntax.
57 * This structure keeps track of pid/lwp specifications. If there are no LWPs
58 * specified, then 'lwps' will be NULL.
60 typedef struct proc_set {
61 pid_t pid;
62 const char *lwps;
63 } proc_set_t;
66 * Function prototypes for static routines in this file.
68 void setup_basetime(hrtime_t, struct timeval *);
69 int xcreat(char *);
70 void setoutput(int);
71 void report(private_t *, time_t);
72 void prtim(timestruc_t *);
73 void pids(char *, proc_set_t *);
74 void psargs(private_t *);
75 int control(private_t *, pid_t);
76 int grabit(private_t *, proc_set_t *);
77 void release(private_t *, pid_t);
78 void intr(int);
79 int wait4all(void);
80 void letgo(private_t *);
81 void child_to_file();
82 void file_to_parent();
83 void per_proc_init();
84 int lib_sort(const void *, const void *);
85 int key_sort(const void *, const void *);
87 void *worker_thread(void *);
88 void main_thread(int);
91 * Test for empty set.
92 * is_empty() should not be called directly.
94 int is_empty(const uint32_t *, size_t);
95 #define isemptyset(sp) \
96 is_empty((uint32_t *)(sp), sizeof (*(sp)) / sizeof (uint32_t))
99 * OR the second set into the first set.
100 * or_set() should not be called directly.
102 void or_set(uint32_t *, const uint32_t *, size_t);
103 #define prorset(sp1, sp2) \
104 or_set((uint32_t *)(sp1), (uint32_t *)(sp2), \
105 sizeof (*(sp1)) / sizeof (uint32_t))
107 /* fetch or allocate thread-private data */
108 private_t *
109 get_private()
111 void *value;
112 private_t *pri = NULL;
114 if (thr_getspecific(private_key, &value) == 0)
115 pri = value;
116 if (pri == NULL) {
117 pri = my_malloc(sizeof (*pri), NULL);
118 (void) memset(pri, 0, sizeof (*pri));
119 pri->sys_path = my_malloc(pri->sys_psize = 16, NULL);
120 pri->sys_string = my_malloc(pri->sys_ssize = 32, NULL);
121 if (thr_setspecific(private_key, pri) == ENOMEM)
122 abend("memory allocation failure", NULL);
124 return (pri);
127 /* destructor function for thread-private data */
128 void
129 free_private(void *value)
131 private_t *pri = value;
133 free(pri->sys_path);
134 free(pri->sys_string);
135 free(pri->exec_string);
136 free(pri->str_buffer);
137 free(pri);
141 * This is called by the main thread (via create_thread())
142 * and is also called from other threads in worker_thread()
143 * while holding truss_lock. No further locking is required.
145 void
146 insert_lwpid(lwpid_t lwpid)
148 int i;
150 truss_nlwp++;
151 for (i = 0; i < truss_maxlwp; i++) {
152 if (truss_lwpid[i] == 0)
153 break;
155 if (i == truss_maxlwp) {
156 /* double the size of the array */
157 truss_lwpid = my_realloc(truss_lwpid,
158 truss_maxlwp * 2 * sizeof (lwpid_t), NULL);
159 (void) memset(&truss_lwpid[truss_maxlwp], 0,
160 truss_maxlwp * sizeof (lwpid_t));
161 truss_maxlwp *= 2;
163 truss_lwpid[i] = lwpid;
167 * This is called from the first worker thread to encounter one of
168 * (leave_hung || interrupt || sigusr1). It must notify all other
169 * worker threads of the same condition. truss_lock is held.
171 void
172 broadcast_signals(void)
174 static int int_notified = FALSE;
175 static int usr1_notified = FALSE;
176 static int usr2_notified = FALSE;
177 lwpid_t my_id = thr_self();
178 lwpid_t lwpid;
179 int i;
181 if (interrupt && !int_notified) {
182 int_notified = TRUE;
183 for (i = 0; i < truss_maxlwp; i++) {
184 if ((lwpid = truss_lwpid[i]) != 0 && lwpid != my_id)
185 (void) thr_kill(lwpid, interrupt);
188 if (sigusr1 && !usr1_notified) {
189 usr1_notified = TRUE;
190 for (i = 0; i < truss_maxlwp; i++) {
191 if ((lwpid = truss_lwpid[i]) != 0 && lwpid != my_id)
192 (void) thr_kill(lwpid, SIGUSR1);
195 if (leave_hung && !usr2_notified) {
196 usr2_notified = TRUE;
197 for (i = 0; i < truss_maxlwp; i++) {
198 if ((lwpid = truss_lwpid[i]) != 0 && lwpid != my_id)
199 (void) thr_kill(lwpid, SIGUSR2);
204 static struct ps_lwphandle *
205 grab_lwp(lwpid_t who)
207 struct ps_lwphandle *Lwp;
208 int gcode;
210 if ((Lwp = Lgrab(Proc, who, &gcode)) == NULL) {
211 if (gcode != G_NOPROC) {
212 (void) fprintf(stderr,
213 "%s: cannot grab LWP %u in process %d,"
214 " reason: %s\n",
215 command, who, (int)Pstatus(Proc)->pr_pid,
216 Lgrab_error(gcode));
217 interrupt = SIGTERM; /* post an interrupt */
220 return (Lwp);
224 * Iteration function called for each initial lwp in the controlled process.
226 /* ARGSUSED */
228 create_thread(void *arg, const lwpstatus_t *Lsp)
230 struct ps_lwphandle *new_Lwp;
231 lwpid_t lwpid;
232 int *count = arg;
234 if (lwptrace(Pstatus(Proc)->pr_pid, Lsp->pr_lwpid))
235 *count += 1;
237 if ((new_Lwp = grab_lwp(Lsp->pr_lwpid)) != NULL) {
238 if (thr_create(NULL, 0, worker_thread, new_Lwp,
239 THR_BOUND | THR_SUSPENDED, &lwpid) != 0)
240 abend("cannot create lwp to follow child lwp", NULL);
241 insert_lwpid(lwpid);
243 return (0);
247 main(int argc, char *argv[])
249 private_t *pri;
250 struct tms tms;
251 struct rlimit rlim;
252 int ofd = -1;
253 int opt;
254 int i;
255 int first;
256 int errflg = FALSE;
257 int badname = FALSE;
258 proc_set_t *grab = NULL;
259 const pstatus_t *Psp;
260 const lwpstatus_t *Lsp;
261 int sharedmem;
263 /* a few of these need to be initialized to NULL */
264 Cp = NULL;
265 fcall_tbl = NULL;
268 * Make sure fd's 0, 1, and 2 are allocated,
269 * just in case truss was invoked from init.
271 while ((i = open("/dev/null", O_RDWR)) >= 0 && i < 2)
273 if (i > 2)
274 (void) close(i);
276 starttime = times(&tms); /* for elapsed timing */
278 /* this should be per-traced-process */
279 pagesize = sysconf(_SC_PAGESIZE);
281 /* command name (e.g., "truss") */
282 if ((command = strrchr(argv[0], '/')) != NULL)
283 command++;
284 else
285 command = argv[0];
287 /* set up the initial private data */
288 (void) mutex_init(&truss_lock, USYNC_THREAD, NULL);
289 (void) mutex_init(&count_lock, USYNC_THREAD, NULL);
290 (void) cond_init(&truss_cv, USYNC_THREAD, NULL);
291 if (thr_keycreate(&private_key, free_private) == ENOMEM)
292 abend("memory allocation failure", NULL);
293 pri = get_private();
295 Euid = geteuid();
296 Egid = getegid();
297 Ruid = getuid();
298 Rgid = getgid();
299 ancestor = getpid();
301 prfillset(&trace); /* default: trace all system calls */
302 premptyset(&verbose); /* default: no syscall verbosity */
303 premptyset(&rawout); /* default: no raw syscall interpretation */
305 prfillset(&signals); /* default: trace all signals */
307 prfillset(&faults); /* default: trace all faults */
308 prdelset(&faults, FLTPAGE); /* except this one */
310 premptyset(&readfd); /* default: dump no buffers */
311 premptyset(&writefd);
313 premptyset(&syshang); /* default: hang on no system calls */
314 premptyset(&sighang); /* default: hang on no signals */
315 premptyset(&flthang); /* default: hang on no faults */
317 (void) sigemptyset(&emptyset); /* for unblocking all signals */
318 (void) sigfillset(&fillset); /* for blocking all signals */
320 #define OPTIONS "FpfcaeildDEht:T:v:x:s:S:m:M:u:U:r:w:o:"
321 while ((opt = getopt(argc, argv, OPTIONS)) != EOF) {
322 switch (opt) {
323 case 'F': /* force grabbing (no O_EXCL) */
324 Fflag = PGRAB_FORCE;
325 break;
326 case 'p': /* grab processes */
327 pflag = TRUE;
328 break;
329 case 'f': /* follow children */
330 fflag = TRUE;
331 break;
332 case 'c': /* don't trace, just count */
333 cflag = TRUE;
334 iflag = TRUE; /* implies no interruptable syscalls */
335 break;
336 case 'a': /* display argument lists */
337 aflag = TRUE;
338 break;
339 case 'e': /* display environments */
340 eflag = TRUE;
341 break;
342 case 'i': /* don't show interruptable syscalls */
343 iflag = TRUE;
344 break;
345 case 'l': /* show lwp id for each syscall */
346 lflag = TRUE;
347 break;
348 case 'h': /* debugging: report hash stats */
349 hflag = TRUE;
350 break;
351 case 'd': /* show time stamps */
352 dflag = TRUE;
353 break;
354 case 'D': /* show time deltas */
355 Dflag = TRUE;
356 break;
357 case 'E':
358 Eflag = TRUE; /* show syscall times */
359 break;
360 case 't': /* system calls to trace */
361 if (syslist(optarg, &trace, &tflag))
362 badname = TRUE;
363 break;
364 case 'T': /* system calls to hang process */
365 if (syslist(optarg, &syshang, &Tflag))
366 badname = TRUE;
367 break;
368 case 'v': /* verbose interpretation of syscalls */
369 if (syslist(optarg, &verbose, &vflag))
370 badname = TRUE;
371 break;
372 case 'x': /* raw interpretation of syscalls */
373 if (syslist(optarg, &rawout, &xflag))
374 badname = TRUE;
375 break;
376 case 's': /* signals to trace */
377 if (siglist(pri, optarg, &signals, &sflag))
378 badname = TRUE;
379 break;
380 case 'S': /* signals to hang process */
381 if (siglist(pri, optarg, &sighang, &Sflag))
382 badname = TRUE;
383 break;
384 case 'm': /* machine faults to trace */
385 if (fltlist(optarg, &faults, &mflag))
386 badname = TRUE;
387 break;
388 case 'M': /* machine faults to hang process */
389 if (fltlist(optarg, &flthang, &Mflag))
390 badname = TRUE;
391 break;
392 case 'u': /* user library functions to trace */
393 if (liblist(optarg, 0))
394 badname = TRUE;
395 break;
396 case 'U': /* user library functions to hang */
397 if (liblist(optarg, 1))
398 badname = TRUE;
399 break;
400 case 'r': /* show contents of read(fd) */
401 if (fdlist(optarg, &readfd))
402 badname = TRUE;
403 break;
404 case 'w': /* show contents of write(fd) */
405 if (fdlist(optarg, &writefd))
406 badname = TRUE;
407 break;
408 case 'o': /* output file for trace */
409 oflag = TRUE;
410 if (ofd >= 0)
411 (void) close(ofd);
412 if ((ofd = xcreat(optarg)) < 0) {
413 perror(optarg);
414 badname = TRUE;
416 break;
417 default:
418 errflg = TRUE;
419 break;
423 if (badname)
424 exit(2);
426 /* if -a or -e was specified, force tracing of exec() */
427 if (aflag || eflag)
428 praddset(&trace, SYS_execve);
431 * Make sure that all system calls, signals, and machine faults
432 * that hang the process are added to their trace sets.
434 prorset(&trace, &syshang);
435 prorset(&signals, &sighang);
436 prorset(&faults, &flthang);
438 argc -= optind;
439 argv += optind;
441 /* collect the specified process ids */
442 if (pflag && argc > 0) {
443 grab = my_malloc(argc * sizeof (proc_set_t),
444 "memory for process-ids");
445 while (argc-- > 0)
446 pids(*argv++, grab);
449 if (errflg || (argc <= 0 && ngrab <= 0)) {
450 (void) fprintf(stderr,
451 "usage:\t%s [-fcaeildDEF] [-[tTvx] [!]syscalls] [-[sS] [!]signals]\\\n",
452 command);
453 (void) fprintf(stderr,
454 "\t[-[mM] [!]faults] [-[rw] [!]fds] [-[uU] [!]libs:[:][!]funcs]\\\n");
455 (void) fprintf(stderr,
456 "\t[-o outfile] command | -p pid[/lwps] ...\n");
457 exit(2);
460 if (argc > 0) { /* create the controlled process */
461 int err;
462 char path[PATH_MAX];
464 Proc = Pcreate(argv[0], &argv[0], &err, path, sizeof (path));
465 if (Proc == NULL) {
466 switch (err) {
467 case C_PERM:
468 (void) fprintf(stderr,
469 "%s: cannot trace set-id or "
470 "unreadable object file: %s\n",
471 command, path);
472 break;
473 case C_LP64:
474 (void) fprintf(stderr,
475 "%s: cannot control _LP64 "
476 "program: %s\n",
477 command, path);
478 break;
479 case C_NOEXEC:
480 (void) fprintf(stderr,
481 "%s: cannot execute program: %s\n",
482 command, argv[0]);
483 break;
484 case C_NOENT:
485 (void) fprintf(stderr,
486 "%s: cannot find program: %s\n",
487 command, argv[0]);
488 break;
489 case C_STRANGE:
490 break;
491 default:
492 (void) fprintf(stderr, "%s: %s\n",
493 command, Pcreate_error(err));
494 break;
496 exit(2);
498 if (fflag || Dynpat != NULL)
499 (void) Psetflags(Proc, PR_FORK);
500 else
501 (void) Punsetflags(Proc, PR_FORK);
502 Psp = Pstatus(Proc);
503 Lsp = &Psp->pr_lwp;
504 pri->lwpstat = Lsp;
505 data_model = Psp->pr_dmodel;
506 created = Psp->pr_pid;
507 make_pname(pri, 0);
508 (void) sysentry(pri, 1);
509 pri->length = 0;
510 if (!cflag && prismember(&trace, SYS_execve)) {
511 pri->exec_string = my_realloc(pri->exec_string,
512 strlen(pri->sys_string) + 1, NULL);
513 (void) strcpy(pri->exec_pname, pri->pname);
514 (void) strcpy(pri->exec_string, pri->sys_string);
515 pri->length += strlen(pri->sys_string);
516 pri->exec_lwpid = pri->lwpstat->pr_lwpid;
517 pri->sys_leng = 0;
518 *pri->sys_string = '\0';
520 pri->syslast = Psp->pr_stime;
521 pri->usrlast = Psp->pr_utime;
525 * Now that we have created the victim process,
526 * give ourself a million file descriptors.
527 * This is enough to deal with a multithreaded
528 * victim process that has half a million lwps.
530 rlim.rlim_cur = 1024 * 1024;
531 rlim.rlim_max = 1024 * 1024;
532 if ((Euid != 0 || setrlimit(RLIMIT_NOFILE, &rlim) != 0) &&
533 getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
535 * Failing the million, give ourself as many
536 * file descriptors as we can get.
538 rlim.rlim_cur = rlim.rlim_max;
539 (void) setrlimit(RLIMIT_NOFILE, &rlim);
541 (void) enable_extended_FILE_stdio(-1, -1);
543 setoutput(ofd); /* establish truss output */
544 istty = isatty(1);
546 if (setvbuf(stdout, NULL, _IOFBF, MYBUFSIZ) != 0)
547 abend("setvbuf() failure", NULL);
550 * Set up signal dispositions.
552 if (created && (oflag || !istty)) { /* ignore interrupts */
553 (void) sigset(SIGHUP, SIG_IGN);
554 (void) sigset(SIGINT, SIG_IGN);
555 (void) sigset(SIGQUIT, SIG_IGN);
556 } else { /* receive interrupts */
557 if (sigset(SIGHUP, SIG_IGN) == SIG_DFL)
558 (void) sigset(SIGHUP, intr);
559 if (sigset(SIGINT, SIG_IGN) == SIG_DFL)
560 (void) sigset(SIGINT, intr);
561 if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL)
562 (void) sigset(SIGQUIT, intr);
564 (void) sigset(SIGTERM, intr);
565 (void) sigset(SIGUSR1, intr);
566 (void) sigset(SIGUSR2, intr);
567 (void) sigset(SIGPIPE, intr);
569 /* don't accumulate zombie children */
570 (void) sigset(SIGCLD, SIG_IGN);
572 /* create shared mem space for global mutexes */
574 sharedmem = (fflag || Dynpat != NULL || ngrab > 1);
575 gps = mmap(NULL, sizeof (struct global_psinfo),
576 PROT_READ|PROT_WRITE,
577 MAP_ANON | (sharedmem? MAP_SHARED : MAP_PRIVATE),
578 -1, (off_t)0);
579 if (gps == MAP_FAILED)
580 abend("cannot allocate ", "memory for counts");
581 i = sharedmem? USYNC_PROCESS : USYNC_THREAD;
582 (void) mutex_init(&gps->ps_mutex0, i, NULL);
583 (void) mutex_init(&gps->ps_mutex1, i, NULL);
584 (void) mutex_init(&gps->fork_lock, i, NULL);
585 (void) cond_init(&gps->fork_cv, i, NULL);
588 /* config tmp file if counting and following */
589 if (fflag && cflag) {
590 char *tmps = tempnam("/var/tmp", "truss");
591 sfd = open(tmps, O_CREAT|O_APPEND|O_EXCL|O_RDWR, 0600);
592 if (sfd == -1)
593 abend("Error creating tmpfile", NULL);
594 if (unlink(tmps) == -1)
595 abend("Error unlinking tmpfile", NULL);
596 free(tmps);
597 tmps = NULL;
600 if (created) {
601 per_proc_init();
602 procadd(created, NULL);
603 show_cred(pri, TRUE, FALSE);
604 } else { /* grab the specified processes */
605 int gotone = FALSE;
607 i = 0;
608 while (i < ngrab) { /* grab first process */
609 if (grabit(pri, &grab[i++])) {
610 Psp = Pstatus(Proc);
611 Lsp = &Psp->pr_lwp;
612 gotone = TRUE;
613 break;
616 if (!gotone)
617 abend(NULL, NULL);
618 per_proc_init();
619 while (i < ngrab) { /* grab the remainder */
620 proc_set_t *set = &grab[i++];
622 (void) mutex_lock(&truss_lock);
623 switch (fork()) {
624 case -1:
625 (void) fprintf(stderr,
626 "%s: cannot fork to control process, pid# %d\n",
627 command, (int)set->pid);
628 /* FALLTHROUGH */
629 default:
630 (void) mutex_unlock(&truss_lock);
631 continue; /* parent carries on */
633 case 0: /* child grabs process */
634 (void) mutex_unlock(&truss_lock);
635 Pfree(Proc);
636 descendent = TRUE;
637 if (grabit(pri, set)) {
638 Psp = Pstatus(Proc);
639 Lsp = &Psp->pr_lwp;
640 per_proc_init();
641 break;
643 exit(2);
645 break;
647 free(grab);
652 * If running setuid-root, become root for real to avoid
653 * affecting the per-user limitation on the maximum number
654 * of processes (one benefit of running setuid-root).
656 if (Rgid != Egid)
657 (void) setgid(Egid);
658 if (Ruid != Euid)
659 (void) setuid(Euid);
661 if (!created && aflag && prismember(&trace, SYS_execve)) {
662 psargs(pri);
663 Flush();
666 if (created && Pstate(Proc) != PS_STOP) /* assertion */
667 if (!(interrupt | sigusr1))
668 abend("ASSERT error: process is not stopped", NULL);
670 traceeven = trace; /* trace these system calls */
672 /* trace these regardless, even if we don't report results */
673 praddset(&traceeven, SYS_exit);
674 praddset(&traceeven, SYS_lwp_create);
675 praddset(&traceeven, SYS_lwp_exit);
676 praddset(&traceeven, SYS_execve);
677 praddset(&traceeven, SYS_openat);
678 praddset(&traceeven, SYS_open);
679 praddset(&traceeven, SYS_vfork);
680 praddset(&traceeven, SYS_forksys);
682 /* for I/O buffer dumps, force tracing of read()s and write()s */
683 if (!isemptyset(&readfd)) {
684 praddset(&traceeven, SYS_read);
685 praddset(&traceeven, SYS_readv);
686 praddset(&traceeven, SYS_pread);
687 praddset(&traceeven, SYS_recv);
688 praddset(&traceeven, SYS_recvfrom);
689 praddset(&traceeven, SYS_recvmsg);
691 if (!isemptyset(&writefd)) {
692 praddset(&traceeven, SYS_write);
693 praddset(&traceeven, SYS_writev);
694 praddset(&traceeven, SYS_pwrite);
695 praddset(&traceeven, SYS_send);
696 praddset(&traceeven, SYS_sendto);
697 praddset(&traceeven, SYS_sendmsg);
700 if (cflag || Eflag) {
701 Psetsysentry(Proc, &traceeven);
703 Psetsysexit(Proc, &traceeven);
705 /* special case -- cannot trace sysexit because context is changed */
706 if (prismember(&trace, SYS_context)) {
707 (void) Psysentry(Proc, SYS_context, TRUE);
708 (void) Psysexit(Proc, SYS_context, FALSE);
709 prdelset(&traceeven, SYS_context);
712 /* special case -- trace exec() on entry to get the args */
713 (void) Psysentry(Proc, SYS_execve, TRUE);
715 /* special case -- sysexit never reached */
716 (void) Psysentry(Proc, SYS_exit, TRUE);
717 (void) Psysentry(Proc, SYS_lwp_exit, TRUE);
718 (void) Psysexit(Proc, SYS_exit, FALSE);
719 (void) Psysexit(Proc, SYS_lwp_exit, FALSE);
721 Psetsignal(Proc, &signals); /* trace these signals */
722 Psetfault(Proc, &faults); /* trace these faults */
724 /* for function call tracing */
725 if (Dynpat != NULL) {
726 /* trace these regardless, to deal with function calls */
727 (void) Pfault(Proc, FLTBPT, TRUE);
728 (void) Pfault(Proc, FLTTRACE, TRUE);
730 /* needed for x86 */
731 (void) Psetflags(Proc, PR_BPTADJ);
734 * Find functions and set breakpoints on grabbed process.
735 * A process stopped on exec() gets its breakpoints set below.
737 if ((Lsp->pr_why != PR_SYSENTRY &&
738 Lsp->pr_why != PR_SYSEXIT) ||
739 Lsp->pr_what != SYS_execve) {
740 establish_breakpoints();
741 establish_stacks();
746 * Use asynchronous-stop for multithreaded truss.
747 * truss runs one lwp for each lwp in the target process.
749 (void) Psetflags(Proc, PR_ASYNC);
751 /* flush out all tracing flags now. */
752 Psync(Proc);
755 * If we grabbed a running process, set it running again.
756 * Since we are tracing lwp_create() and lwp_exit(), the
757 * lwps will not change in the process until we create all
758 * of the truss worker threads.
759 * We leave a created process stopped so its exec() can be reported.
761 first = created? FALSE : TRUE;
762 if (!created &&
763 ((Pstate(Proc) == PS_STOP && Lsp->pr_why == PR_REQUESTED) ||
764 (Lsp->pr_flags & PR_DSTOP)))
765 first = FALSE;
767 main_thread(first);
768 return (0);
772 * Called from main() and from control() after fork().
774 void
775 main_thread(int first)
777 private_t *pri = get_private();
778 struct tms tms;
779 int flags;
780 int retc;
781 int i;
782 int count;
785 * Block all signals in the main thread.
786 * Some worker thread will receive signals.
788 (void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL);
791 * If we are dealing with a previously hung process,
792 * arrange not to leave it hung on the same system call.
794 primary_lwp = (first && Pstate(Proc) == PS_STOP)?
795 Pstatus(Proc)->pr_lwp.pr_lwpid : 0;
798 * Create worker threads to match the lwps in the target process.
800 truss_nlwp = 0;
801 truss_maxlwp = 1;
802 truss_lwpid = my_realloc(truss_lwpid, sizeof (lwpid_t), NULL);
803 truss_lwpid[0] = 0;
804 count = 0;
805 (void) Plwp_iter(Proc, create_thread, &count);
807 if (count == 0) {
808 (void) printf("(Warning: no matching active LWPs found, "
809 "waiting)\n");
810 Flush();
814 * Set all of the truss worker threads running now.
816 (void) mutex_lock(&truss_lock);
817 for (i = 0; i < truss_maxlwp; i++) {
818 if (truss_lwpid[i])
819 (void) thr_continue(truss_lwpid[i]);
821 (void) mutex_unlock(&truss_lock);
824 * Wait until all worker threads terminate.
826 while (thr_join(0, NULL, NULL) == 0)
827 continue;
829 (void) Punsetflags(Proc, PR_ASYNC);
830 Psync(Proc);
831 if (sigusr1)
832 letgo(pri);
833 flags = PRELEASE_CLEAR;
834 if (leave_hung)
835 flags |= PRELEASE_HANG;
836 Prelease(Proc, flags);
838 procdel();
839 retc = (leave_hung? 0 : wait4all());
841 if (!descendent) {
842 interrupt = 0; /* another interrupt kills the report */
843 if (cflag) {
844 if (fflag)
845 file_to_parent();
846 report(pri, times(&tms) - starttime);
848 } else if (cflag && fflag) {
849 child_to_file();
852 exit(retc); /* exit with exit status of created process, else 0 */
855 void *
856 worker_thread(void *arg)
858 struct ps_lwphandle *Lwp = (struct ps_lwphandle *)arg;
859 const pstatus_t *Psp = Pstatus(Proc);
860 const lwpstatus_t *Lsp = Lstatus(Lwp);
861 struct syscount *scp;
862 lwpid_t who = Lsp->pr_lwpid;
863 int first = (who == primary_lwp);
864 private_t *pri = get_private();
865 int req_flag = 0;
866 int leave_it_hung = FALSE;
867 int reset_traps = FALSE;
868 int gcode;
869 int what;
870 int ow_in_effect = 0;
871 long ow_syscall = 0;
872 long ow_subcode = 0;
873 char *ow_string = NULL;
874 sysset_t full_set;
875 sysset_t running_set;
876 int dotrace = lwptrace(Psp->pr_pid, Lsp->pr_lwpid);
878 pri->Lwp = Lwp;
879 pri->lwpstat = Lsp;
880 pri->syslast = Lsp->pr_stime;
881 pri->usrlast = Lsp->pr_utime;
882 make_pname(pri, 0);
884 prfillset(&full_set);
886 /* we were created with all signals blocked; unblock them */
887 (void) thr_sigsetmask(SIG_SETMASK, &emptyset, NULL);
890 * Run this loop until the victim lwp terminates or we receive
891 * a termination condition (leave_hung | interrupt | sigusr1).
893 for (;;) {
894 if (interrupt | sigusr1) {
895 (void) Lstop(Lwp, MILLISEC);
896 if (Lstate(Lwp) == PS_RUN)
897 break;
899 if (Lstate(Lwp) == PS_RUN) {
900 /* millisecond timeout is for sleeping syscalls */
901 uint_t tout = (iflag || req_flag)? 0 : MILLISEC;
904 * If we are to leave this lwp stopped in sympathy
905 * with another lwp that has been left hung, or if
906 * we have been interrupted or instructed to release
907 * our victim process, and this lwp is stopped but
908 * not on an event of interest to /proc, then just
909 * leave it in that state.
911 if ((leave_hung | interrupt | sigusr1) &&
912 (Lsp->pr_flags & (PR_STOPPED|PR_ISTOP))
913 == PR_STOPPED)
914 break;
916 (void) Lwait(Lwp, tout);
917 if (Lstate(Lwp) == PS_RUN &&
918 tout != 0 && !(interrupt | sigusr1)) {
919 (void) mutex_lock(&truss_lock);
920 if ((Lsp->pr_flags & PR_STOPPED) &&
921 Lsp->pr_why == PR_JOBCONTROL)
922 req_flag = jobcontrol(pri, dotrace);
923 else
924 req_flag = requested(pri, req_flag,
925 dotrace);
926 (void) mutex_unlock(&truss_lock);
928 continue;
930 data_model = Psp->pr_dmodel;
931 if (Lstate(Lwp) == PS_UNDEAD)
932 break;
933 if (Lstate(Lwp) == PS_LOST) { /* we lost control */
935 * After exec(), only one LWP remains in the process.
936 * /proc makes the thread following that LWP receive
937 * EAGAIN (PS_LOST) if the program being exec()ed
938 * is a set-id program. Every other controlling
939 * thread receives ENOENT (because its LWP vanished).
940 * We are the controlling thread for the exec()ing LWP.
941 * We must wait until all of our siblings terminate
942 * before attempting to reopen the process.
944 (void) mutex_lock(&truss_lock);
945 while (truss_nlwp > 1)
946 (void) cond_wait(&truss_cv, &truss_lock);
947 if (Preopen(Proc) == 0) { /* we got control back */
949 * We have to free and re-grab the LWP.
950 * The process is guaranteed to be at exit
951 * from exec() or execve() and have only
952 * one LWP, namely this one, and the LWP
953 * is guaranteed to have lwpid == 1.
954 * This "cannot fail".
956 who = 1;
957 Lfree(Lwp);
958 pri->Lwp = Lwp =
959 Lgrab(Proc, who, &gcode);
960 if (Lwp == NULL)
961 abend("Lgrab error: ",
962 Lgrab_error(gcode));
963 pri->lwpstat = Lsp = Lstatus(Lwp);
964 (void) mutex_unlock(&truss_lock);
965 continue;
968 /* we really lost it */
969 if (pri->exec_string && *pri->exec_string) {
970 if (pri->exec_pname[0] != '\0')
971 (void) fputs(pri->exec_pname, stdout);
972 timestamp(pri);
973 (void) fputs(pri->exec_string, stdout);
974 (void) fputc('\n', stdout);
975 } else if (pri->length) {
976 (void) fputc('\n', stdout);
978 if (pri->sys_valid)
979 (void) printf(
980 "%s\t*** cannot trace across exec() of %s ***\n",
981 pri->pname, pri->sys_path);
982 else
983 (void) printf(
984 "%s\t*** lost control of process ***\n",
985 pri->pname);
986 pri->length = 0;
987 Flush();
988 (void) mutex_unlock(&truss_lock);
989 break;
991 if (Lstate(Lwp) != PS_STOP) {
992 (void) fprintf(stderr,
993 "%s: state = %d\n", command, Lstate(Lwp));
994 abend(pri->pname, "uncaught status of subject lwp");
997 make_pname(pri, 0);
999 (void) mutex_lock(&truss_lock);
1001 what = Lsp->pr_what;
1002 req_flag = 0;
1004 switch (Lsp->pr_why) {
1005 case PR_REQUESTED:
1006 break;
1007 case PR_SIGNALLED:
1008 req_flag = signalled(pri, req_flag, dotrace);
1009 if (Sflag && !first && prismember(&sighang, what))
1010 leave_it_hung = TRUE;
1011 break;
1012 case PR_FAULTED:
1013 if (what == FLTBPT) {
1014 int rval;
1016 (void) Pstop(Proc, 0);
1017 rval = function_trace(pri, first, 0, dotrace);
1018 if (rval == 1)
1019 leave_it_hung = TRUE;
1020 if (rval >= 0)
1021 break;
1023 if (faulted(pri, dotrace) &&
1024 Mflag && !first && prismember(&flthang, what))
1025 leave_it_hung = TRUE;
1026 break;
1027 case PR_JOBCONTROL: /* can't happen except first time */
1028 req_flag = jobcontrol(pri, dotrace);
1029 break;
1030 case PR_SYSENTRY:
1031 /* protect ourself from operating system error */
1032 if (what <= 0 || what > PRMAXSYS)
1033 what = PRMAXSYS;
1034 pri->length = 0;
1036 * ow_in_effect checks to see whether or not we
1037 * are attempting to quantify the time spent in
1038 * a one way system call. This is necessary as
1039 * some system calls never return, yet it is desireable
1040 * to determine how much time the traced process
1041 * spends in these calls. To do this, a one way
1042 * flag is set on SYSENTRY when the call is recieved.
1043 * After this, the call mask for the SYSENTRY events
1044 * is filled so that the traced process will stop
1045 * on the entry to the very next system call.
1046 * This appears to the the best way to determine
1047 * system time elapsed between a one way system call.
1048 * Once the next call occurs, values that have been
1049 * stashed are used to record the correct syscall
1050 * and time, and the SYSENTRY event mask is restored
1051 * so that the traced process may continue.
1053 if (dotrace && ow_in_effect) {
1054 if (cflag) {
1055 (void) mutex_lock(&count_lock);
1056 scp = Cp->syscount[ow_syscall];
1057 if (ow_subcode != -1)
1058 scp += ow_subcode;
1059 scp->count++;
1060 accumulate(&scp->stime,
1061 &Lsp->pr_stime, &pri->syslast);
1062 accumulate(&Cp->usrtotal,
1063 &Lsp->pr_utime, &pri->usrlast);
1064 pri->syslast = Lsp->pr_stime;
1065 pri->usrlast = Lsp->pr_utime;
1066 (void) mutex_unlock(&count_lock);
1067 } else if (Eflag) {
1068 putpname(pri);
1069 timestamp(pri);
1070 (void) printf("%s\n", ow_string);
1071 free(ow_string);
1072 ow_string = NULL;
1073 pri->syslast = Lsp->pr_stime;
1075 ow_in_effect = 0;
1076 Psetsysentry(Proc, &running_set);
1080 * Special cases. Most syscalls are traced on exit.
1082 switch (what) {
1083 case SYS_exit: /* exit() */
1084 case SYS_lwp_exit: /* lwp_exit() */
1085 case SYS_context: /* [get|set]context() */
1086 if (dotrace && cflag &&
1087 prismember(&trace, what)) {
1088 ow_in_effect = 1;
1089 ow_syscall = what;
1090 ow_subcode = getsubcode(pri);
1091 pri->syslast = Lsp->pr_stime;
1092 running_set =
1093 (Pstatus(Proc))->pr_sysentry;
1094 Psetsysentry(Proc, &full_set);
1095 } else if (dotrace && Eflag &&
1096 prismember(&trace, what)) {
1097 (void) sysentry(pri, dotrace);
1098 ow_in_effect = 1;
1099 ow_string = my_malloc(
1100 strlen(pri->sys_string) + 1, NULL);
1101 (void) strcpy(ow_string,
1102 pri->sys_string);
1103 running_set =
1104 (Pstatus(Proc))->pr_sysentry;
1105 Psetsysentry(Proc, &full_set);
1106 pri->syslast = Lsp->pr_stime;
1107 } else if (dotrace &&
1108 prismember(&trace, what)) {
1109 (void) sysentry(pri, dotrace);
1110 putpname(pri);
1111 timestamp(pri);
1112 pri->length +=
1113 printf("%s\n", pri->sys_string);
1114 Flush();
1116 pri->sys_leng = 0;
1117 *pri->sys_string = '\0';
1119 if (what == SYS_exit)
1120 exit_called = TRUE;
1121 break;
1122 case SYS_execve:
1123 show_cred(pri, FALSE, TRUE);
1124 (void) sysentry(pri, dotrace);
1125 if (dotrace && !cflag &&
1126 prismember(&trace, what)) {
1127 pri->exec_string =
1128 my_realloc(pri->exec_string,
1129 strlen(pri->sys_string) + 1,
1130 NULL);
1131 (void) strcpy(pri->exec_pname,
1132 pri->pname);
1133 (void) strcpy(pri->exec_string,
1134 pri->sys_string);
1135 pri->length += strlen(pri->sys_string);
1136 pri->exec_lwpid = Lsp->pr_lwpid;
1138 pri->sys_leng = 0;
1139 *pri->sys_string = '\0';
1140 break;
1141 default:
1142 if (dotrace && (cflag || Eflag) &&
1143 prismember(&trace, what)) {
1144 pri->syslast = Lsp->pr_stime;
1146 break;
1148 if (dotrace && Tflag && !first &&
1149 (prismember(&syshang, what) ||
1150 (exit_called && prismember(&syshang, SYS_exit))))
1151 leave_it_hung = TRUE;
1152 break;
1153 case PR_SYSEXIT:
1154 /* check for write open of a /proc file */
1155 if (what == SYS_openat || what == SYS_open) {
1156 int readonly;
1158 (void) sysentry(pri, dotrace);
1159 pri->Errno = Lsp->pr_errno;
1160 pri->ErrPriv = Lsp->pr_errpriv;
1161 readonly =
1162 (what == SYS_openat &&
1163 pri->sys_nargs > 2 &&
1164 (pri->sys_args[2]&0x3) == O_RDONLY) ||
1165 (what == SYS_open &&
1166 pri->sys_nargs > 1 &&
1167 (pri->sys_args[1]&0x3) == O_RDONLY);
1168 if ((pri->Errno == 0 || pri->Errno == EBUSY) &&
1169 pri->sys_valid && !readonly) {
1170 int rv = checkproc(pri);
1171 if (rv == 1 && Fflag != PGRAB_FORCE) {
1173 * The process opened itself
1174 * and no -F flag was specified.
1175 * Just print the open() call
1176 * and let go of the process.
1178 if (dotrace && !cflag &&
1179 prismember(&trace, what)) {
1180 putpname(pri);
1181 timestamp(pri);
1182 (void) printf("%s\n",
1183 pri->sys_string);
1184 Flush();
1186 sigusr1 = TRUE;
1187 (void) mutex_unlock(
1188 &truss_lock);
1189 goto out;
1191 if (rv == 2) {
1193 * Process opened someone else.
1194 * The open is being reissued.
1195 * Don't report this one.
1197 pri->sys_leng = 0;
1198 *pri->sys_string = '\0';
1199 pri->sys_nargs = 0;
1200 break;
1204 if (what == SYS_execve && pri->Errno == 0) {
1206 * Refresh the data model on exec() in case it
1207 * is different from the parent. Lwait()
1208 * doesn't update process-wide status, so we
1209 * have to explicitly call Pstopstatus() to get
1210 * the new state.
1212 (void) Pstopstatus(Proc, PCNULL, 0);
1213 data_model = Psp->pr_dmodel;
1215 if (sysexit(pri, dotrace))
1216 Flush();
1217 if (what == SYS_lwp_create && pri->Rval1 != 0) {
1218 struct ps_lwphandle *new_Lwp;
1219 lwpid_t lwpid;
1221 if ((new_Lwp = grab_lwp(pri->Rval1)) != NULL) {
1222 (void) thr_sigsetmask(SIG_SETMASK,
1223 &fillset, NULL);
1224 if (thr_create(NULL, 0, worker_thread,
1225 new_Lwp, THR_BOUND | THR_SUSPENDED,
1226 &lwpid) != 0)
1227 abend("cannot create lwp ",
1228 "to follow child lwp");
1229 insert_lwpid(lwpid);
1230 (void) thr_continue(lwpid);
1231 (void) thr_sigsetmask(SIG_SETMASK,
1232 &emptyset, NULL);
1235 pri->sys_nargs = 0;
1236 if (dotrace && Tflag && !first &&
1237 prismember(&syshang, what))
1238 leave_it_hung = TRUE;
1239 if (what == SYS_execve && pri->Errno == 0) {
1240 is_vfork_child = FALSE;
1241 reset_breakpoints();
1243 * exec() resets the calling LWP's lwpid to 1.
1244 * If the LWP has changed its lwpid, then
1245 * we have to free and re-grab the LWP
1246 * in order to keep libproc consistent.
1247 * This "cannot fail".
1249 if (who != Lsp->pr_lwpid) {
1251 * We must wait for all of our
1252 * siblings to terminate.
1254 while (truss_nlwp > 1)
1255 (void) cond_wait(&truss_cv,
1256 &truss_lock);
1257 who = Lsp->pr_lwpid;
1258 Lfree(Lwp);
1259 pri->Lwp = Lwp =
1260 Lgrab(Proc, who, &gcode);
1261 if (Lwp == NULL)
1262 abend("Lgrab error: ",
1263 Lgrab_error(gcode));
1264 pri->lwpstat = Lsp = Lstatus(Lwp);
1267 break;
1268 default:
1269 req_flag = 0;
1270 (void) fprintf(stderr,
1271 "unknown reason for stopping: %d/%d\n",
1272 Lsp->pr_why, what);
1273 abend(NULL, NULL);
1276 if (pri->child) { /* controlled process fork()ed */
1277 if (fflag || Dynpat != NULL) {
1278 if (Lsp->pr_why == PR_SYSEXIT &&
1279 (Lsp->pr_what == SYS_vfork ||
1280 (Lsp->pr_what == SYS_forksys &&
1281 Lsp->pr_sysarg[0] == 2))) {
1282 is_vfork_child = TRUE;
1283 (void) Pstop(Proc, 0);
1285 if (control(pri, pri->child)) {
1286 (void) mutex_unlock(&truss_lock);
1287 pri->child = 0;
1288 if (!fflag) {
1290 * If this is vfork(), then
1291 * this clears the breakpoints
1292 * in the parent's address space
1293 * as well as in the child's.
1295 clear_breakpoints();
1296 Prelease(Proc, PRELEASE_CLEAR);
1297 _exit(0);
1299 main_thread(FALSE);
1300 /* NOTREACHED */
1304 * Here, we are still the parent truss.
1305 * If the child messes with the breakpoints and
1306 * this is vfork(), we have to set them again.
1308 if (Dynpat != NULL && is_vfork_child && !fflag)
1309 reset_traps = TRUE;
1310 is_vfork_child = FALSE;
1312 pri->child = 0;
1315 if (leave_it_hung) {
1316 (void) mutex_unlock(&truss_lock);
1317 break;
1320 if (reset_traps) {
1322 * To recover from vfork, we must catch the lwp
1323 * that issued the vfork() when it returns to user
1324 * level, with all other lwps remaining stopped.
1325 * For this purpose, we have directed all lwps to
1326 * stop and we now set the vfork()ing lwp running
1327 * with the PRSTEP flag. We expect to capture it
1328 * when it stops again showing PR_FAULTED/FLTTRACE.
1329 * We are holding truss_lock, so no other threads
1330 * in truss will set any other lwps in the victim
1331 * process running.
1333 reset_traps = FALSE;
1334 (void) Lsetrun(Lwp, 0, PRSTEP);
1335 do {
1336 (void) Lwait(Lwp, 0);
1337 } while (Lstate(Lwp) == PS_RUN);
1338 if (Lstate(Lwp) == PS_STOP &&
1339 Lsp->pr_why == PR_FAULTED &&
1340 Lsp->pr_what == FLTTRACE) {
1341 reestablish_traps();
1342 (void) Lsetrun(Lwp, 0, PRCFAULT|PRSTOP);
1343 } else {
1344 (void) printf("%s\t*** Expected PR_FAULTED/"
1345 "FLTTRACE stop following vfork()\n",
1346 pri->pname);
1350 if (Lstate(Lwp) == PS_STOP) {
1351 int flags = 0;
1353 if (interrupt | sigusr1) {
1354 (void) mutex_unlock(&truss_lock);
1355 break;
1358 * If we must leave this lwp hung is sympathy with
1359 * another lwp that is being left hung on purpose,
1360 * then push the state onward toward PR_REQUESTED.
1362 if (leave_hung) {
1363 if (Lsp->pr_why == PR_REQUESTED) {
1364 (void) mutex_unlock(&truss_lock);
1365 break;
1367 flags |= PRSTOP;
1369 if (Lsetrun(Lwp, 0, flags) != 0 &&
1370 Lstate(Lwp) != PS_LOST &&
1371 Lstate(Lwp) != PS_UNDEAD) {
1372 (void) mutex_unlock(&truss_lock);
1373 perror("Lsetrun");
1374 abend("cannot start subject lwp", NULL);
1375 /* NOTREACHED */
1378 first = FALSE;
1380 (void) mutex_unlock(&truss_lock);
1383 out:
1384 /* block all signals in preparation for exiting */
1385 (void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL);
1387 if (Lstate(Lwp) == PS_UNDEAD || Lstate(Lwp) == PS_LOST)
1388 (void) mutex_lock(&truss_lock);
1389 else {
1390 (void) Lstop(Lwp, MILLISEC);
1391 (void) mutex_lock(&truss_lock);
1392 if (Lstate(Lwp) == PS_STOP &&
1393 Lsp->pr_why == PR_FAULTED &&
1394 Lsp->pr_what == FLTBPT)
1395 (void) function_trace(pri, 0, 1, dotrace);
1398 if (dotrace && ow_in_effect) {
1399 if (cflag) {
1400 (void) mutex_lock(&count_lock);
1401 scp = Cp->syscount[ow_syscall];
1402 if (ow_subcode != -1)
1403 scp += ow_subcode;
1404 scp->count++;
1405 accumulate(&scp->stime,
1406 &Lsp->pr_stime, &pri->syslast);
1407 accumulate(&Cp->usrtotal,
1408 &Lsp->pr_utime, &pri->usrlast);
1409 pri->syslast = Lsp->pr_stime;
1410 pri->usrlast = Lsp->pr_utime;
1411 (void) mutex_unlock(&count_lock);
1412 } else if (Eflag) {
1413 putpname(pri);
1414 timestamp(pri);
1415 (void) printf("%s\n", ow_string);
1416 free(ow_string);
1417 ow_string = NULL;
1418 pri->syslast = Lsp->pr_stime;
1420 ow_in_effect = 0;
1421 Psetsysentry(Proc, &running_set);
1424 if (Lstate(Lwp) == PS_UNDEAD || Lstate(Lwp) == PS_LOST) {
1426 * The victim thread has exited or we lost control of
1427 * the process. Remove ourself from the list of all
1428 * truss threads and notify everyone waiting for this.
1430 lwpid_t my_id = thr_self();
1431 int i;
1433 for (i = 0; i < truss_maxlwp; i++) {
1434 if (truss_lwpid[i] == my_id) {
1435 truss_lwpid[i] = 0;
1436 break;
1439 if (--truss_nlwp != 0) {
1440 (void) cond_broadcast(&truss_cv);
1441 } else {
1443 * The last truss worker thread is terminating.
1444 * The address space is gone (UNDEAD) or is
1445 * inaccessible (LOST) so we cannot clear the
1446 * breakpoints. Just report the htable stats.
1448 report_htable_stats();
1450 } else {
1452 * The victim thread is not a zombie thread, and we have not
1453 * lost control of the process. We must have gotten here due
1454 * to (leave_hung || leave_it_hung || interrupt || sigusr1).
1455 * In these cases, we must carefully uninstrument the process
1456 * and either set it running or leave it stopped and abandoned.
1458 static int nstopped = 0;
1459 static int cleared = 0;
1461 if (leave_it_hung)
1462 leave_hung = TRUE;
1463 if ((leave_hung | interrupt | sigusr1) == 0)
1464 abend("(leave_hung | interrupt | sigusr1) == 0", NULL);
1467 * The first truss thread through here needs to instruct all
1468 * application threads to stop -- they're not necessarily
1469 * going to stop on their own.
1471 if (nstopped++ == 0)
1472 (void) Pdstop(Proc);
1475 * Notify all other worker threads about the reason
1476 * for being here (leave_hung || interrupt || sigusr1).
1478 broadcast_signals();
1481 * Once the last thread has reached this point, then and
1482 * only then is it safe to remove breakpoints and other
1483 * instrumentation. Since breakpoints are executed without
1484 * truss_lock held, a monitor thread can't exit until all
1485 * breakpoints have been removed, and we can't be sure the
1486 * procedure to execute a breakpoint won't temporarily
1487 * reinstall a breakpont. Accordingly, we need to wait
1488 * until all threads are in a known state.
1490 while (nstopped != truss_nlwp)
1491 (void) cond_wait(&truss_cv, &truss_lock);
1494 * All truss threads have reached this point.
1495 * One of them clears the breakpoints and
1496 * wakes up everybody else to finish up.
1498 if (cleared++ == 0) {
1500 * All threads should already be stopped,
1501 * but just to be safe...
1503 (void) Pstop(Proc, MILLISEC);
1504 clear_breakpoints();
1505 (void) Psysexit(Proc, SYS_vfork, FALSE);
1506 (void) Psysexit(Proc, SYS_forksys, FALSE);
1507 (void) Punsetflags(Proc, PR_FORK);
1508 Psync(Proc);
1509 fflag = 0;
1510 (void) cond_broadcast(&truss_cv);
1513 if (!leave_hung && Lstate(Lwp) == PS_STOP)
1514 (void) Lsetrun(Lwp, 0, 0);
1517 (void) Lfree(Lwp);
1518 (void) mutex_unlock(&truss_lock);
1519 return (NULL);
1523 * Give a base date for time stamps, adjusted to the
1524 * stop time of the selected (first or created) process.
1526 void
1527 setup_basetime(hrtime_t basehrtime, struct timeval *basedate)
1529 const pstatus_t *Psp = Pstatus(Proc);
1530 (void) mutex_lock(&count_lock);
1531 Cp->basetime = Psp->pr_lwp.pr_tstamp;
1532 (void) mutex_unlock(&count_lock);
1534 if ((dflag|Dflag) && !cflag) {
1535 const struct tm *ptm;
1536 const char *ptime;
1537 const char *pdst;
1538 hrtime_t delta = basehrtime -
1539 ((hrtime_t)Cp->basetime.tv_sec * NANOSEC +
1540 Cp->basetime.tv_nsec);
1542 if (delta > 0) {
1543 basedate->tv_sec -= (time_t)(delta / NANOSEC);
1544 basedate->tv_usec -= (delta % NANOSEC) / 1000;
1545 if (basedate->tv_usec < 0) {
1546 basedate->tv_sec--;
1547 basedate->tv_usec += MICROSEC;
1550 ptm = localtime(&basedate->tv_sec);
1551 ptime = asctime(ptm);
1552 if ((pdst = tzname[ptm->tm_isdst ? 1 : 0]) == NULL)
1553 pdst = "???";
1554 if (dflag) {
1555 (void) printf(
1556 "Base time stamp: %ld.%4.4ld [ %.20s%s %.4s ]\n",
1557 basedate->tv_sec, basedate->tv_usec / 100,
1558 ptime, pdst, ptime + 20);
1559 Flush();
1565 * Performs per-process initializations. If truss is following a victim
1566 * process it will fork additional truss processes to follow new processes
1567 * created. Here is where each new truss process gets its per-process data
1568 * initialized.
1571 void
1572 per_proc_init()
1574 void *pmem;
1575 struct timeval basedate;
1576 hrtime_t basehrtime;
1577 struct syscount *scp;
1578 int i;
1579 timestruc_t c_basetime;
1581 /* Make sure we only configure the basetime for the first truss proc */
1583 if (Cp == NULL) {
1584 pmem = my_malloc(sizeof (struct counts) + maxsyscalls() *
1585 sizeof (struct syscount), NULL);
1586 Cp = (struct counts *)pmem;
1587 basehrtime = gethrtime();
1588 (void) gettimeofday(&basedate, NULL);
1589 setup_basetime(basehrtime, &basedate);
1592 c_basetime = Cp->basetime;
1594 (void) memset(Cp, 0, sizeof (struct counts) + maxsyscalls() *
1595 sizeof (struct syscount));
1597 Cp->basetime = c_basetime;
1599 if (fcall_tbl != NULL)
1600 destroy_hash(fcall_tbl);
1601 fcall_tbl = init_hash(4096);
1603 (void) mutex_lock(&count_lock);
1604 scp = (struct syscount *)(Cp + 1);
1605 for (i = 0; i <= PRMAXSYS; i++) {
1606 Cp->syscount[i] = scp;
1607 scp += nsubcodes(i);
1609 (void) mutex_unlock(&count_lock);
1614 * Writes child state to a tempfile where it can be read and
1615 * accumulated by the parent process. The file descriptor is shared
1616 * among the processes. Ordering of writes does not matter, it is, however,
1617 * necessary to ensure that all writes are atomic.
1620 void
1621 child_to_file()
1623 hiter_t *itr;
1624 hentry_t *ntry;
1625 hdntry_t fentry;
1626 char *s = NULL;
1627 char *t = NULL;
1628 unsigned char *buf = NULL;
1629 size_t bufsz = 0;
1630 size_t i = 0;
1631 size_t j = 0;
1633 /* ensure that we are in fact a child process */
1634 if (!descendent)
1635 return;
1637 /* enumerate fcall_tbl (tbl locked until freed) */
1638 if (Dynpat != NULL) {
1639 itr = iterate_hash(fcall_tbl);
1641 ntry = iter_next(itr);
1642 while (ntry != NULL) {
1643 fentry.type = HD_hashntry;
1644 fentry.count = ntry->count;
1645 s = ntry->key;
1646 t = ntry->lib;
1647 i = strlen(s) + 1;
1648 j = strlen(t) + 1;
1649 fentry.sz_key = i;
1650 fentry.sz_lib = j;
1651 if (i + sizeof (fentry) > bufsz) {
1652 buf = my_realloc(buf, i + j + sizeof (fentry),
1653 NULL);
1654 bufsz = i + j + sizeof (fentry);
1656 (void) memcpy(buf, &fentry, sizeof (fentry));
1657 (void) strlcpy((char *)(buf + sizeof (fentry)), t, j);
1658 (void) strlcpy((char *)(buf + sizeof (fentry) + j),
1659 s, i);
1660 if (write(sfd, buf, sizeof (fentry) + i + j) == -1)
1661 abend("Error writing to tmp file", NULL);
1662 ntry = iter_next(itr);
1664 iter_free(itr);
1667 /* Now write the count/syscount structs down */
1668 bufsz = sizeof (fentry) + (sizeof (struct counts) + maxsyscalls() *
1669 sizeof (struct syscount));
1670 buf = my_realloc(buf, bufsz, NULL);
1671 fentry.type = HD_cts_syscts;
1672 fentry.count = 0; /* undefined, really */
1673 fentry.sz_key = bufsz - sizeof (fentry);
1674 fentry.sz_lib = 0; /* also undefined */
1675 (void) memcpy(buf, &fentry, sizeof (fentry));
1676 (void) memcpy((char *)(buf + sizeof (fentry)), Cp,
1677 bufsz - sizeof (fentry));
1678 if (write(sfd, buf, bufsz) == -1)
1679 abend("Error writing cts/syscts to tmpfile", NULL);
1681 free(buf);
1685 * The following reads entries from the tempfile back to the parent
1686 * so that information can be collected and summed for overall statistics.
1687 * This reads records out of the tempfile. If they are hash table entries,
1688 * the record is merged with the hash table kept by the parent process.
1689 * If the information is a struct count/struct syscount pair, they are
1690 * copied and added into the count/syscount array kept by the parent.
1693 void
1694 file_to_parent()
1696 hdntry_t ntry;
1697 char *s = NULL;
1698 char *t = NULL;
1699 size_t c_offset = 0;
1700 size_t filesz;
1701 size_t t_strsz = 0;
1702 size_t s_strsz = 0;
1703 struct stat fsi;
1705 if (descendent)
1706 return;
1708 if (fstat(sfd, &fsi) == -1)
1709 abend("Error stat-ing tempfile", NULL);
1710 filesz = fsi.st_size;
1712 while (c_offset < filesz) {
1713 /* first get hdntry */
1714 if (pread(sfd, &ntry, sizeof (hdntry_t), c_offset) !=
1715 sizeof (hdntry_t))
1716 abend("Unable to perform full read of hdntry", NULL);
1717 c_offset += sizeof (hdntry_t);
1719 switch (ntry.type) {
1720 case HD_hashntry:
1722 /* first get lib string */
1723 if (ntry.sz_lib > t_strsz) {
1724 t = my_realloc(t, ntry.sz_lib, NULL);
1725 t_strsz = ntry.sz_lib;
1728 (void) memset(t, 0, t_strsz);
1730 /* now actually get the string */
1731 if (pread(sfd, t, ntry.sz_lib, c_offset) != ntry.sz_lib)
1732 abend("Unable to perform full read of lib str",
1733 NULL);
1734 c_offset += ntry.sz_lib;
1736 /* now get key string */
1738 if (ntry.sz_key > s_strsz) {
1739 s = my_realloc(s, ntry.sz_key, NULL);
1740 s_strsz = ntry.sz_key;
1742 (void) memset(s, 0, s_strsz);
1743 if (pread(sfd, s, ntry.sz_key, c_offset) != ntry.sz_key)
1744 abend("Unable to perform full read of key str",
1745 NULL);
1746 c_offset += ntry.sz_key;
1748 add_fcall(fcall_tbl, t, s, ntry.count);
1749 break;
1751 case HD_cts_syscts:
1753 struct counts *ncp;
1754 size_t bfsz = sizeof (struct counts) + maxsyscalls()
1755 * sizeof (struct syscount);
1756 int i;
1757 struct syscount *sscp;
1759 if (ntry.sz_key != bfsz)
1760 abend("cts/syscts size does not sanity check",
1761 NULL);
1762 ncp = my_malloc(ntry.sz_key, NULL);
1764 if (pread(sfd, ncp, ntry.sz_key, c_offset) !=
1765 ntry.sz_key)
1766 abend("Unable to perform full read of cts",
1767 NULL);
1768 c_offset += ntry.sz_key;
1770 sscp = (struct syscount *)(ncp + 1);
1772 (void) mutex_lock(&count_lock);
1774 Cp->usrtotal.tv_sec += ncp->usrtotal.tv_sec;
1775 Cp->usrtotal.tv_nsec += ncp->usrtotal.tv_nsec;
1776 if (Cp->usrtotal.tv_nsec >= NANOSEC) {
1777 Cp->usrtotal.tv_nsec -= NANOSEC;
1778 Cp->usrtotal.tv_sec++;
1780 for (i = 0; i <= PRMAXSYS; i++) {
1781 ncp->syscount[i] = sscp;
1782 sscp += nsubcodes(i);
1785 for (i = 0; i <= PRMAXFAULT; i++) {
1786 Cp->fltcount[i] += ncp->fltcount[i];
1789 for (i = 0; i <= PRMAXSIG; i++) {
1790 Cp->sigcount[i] += ncp->sigcount[i];
1793 for (i = 0; i <= PRMAXSYS; i++) {
1794 struct syscount *scp = Cp->syscount[i];
1795 struct syscount *nscp = ncp->syscount[i];
1796 int n = nsubcodes(i);
1797 int subcode;
1799 for (subcode = 0; subcode < n; subcode++,
1800 scp++, nscp++) {
1801 scp->count += nscp->count;
1802 scp->error += nscp->error;
1803 scp->stime.tv_sec += nscp->stime.tv_sec;
1804 scp->stime.tv_nsec +=
1805 nscp->stime.tv_nsec;
1806 if (scp->stime.tv_nsec >= NANOSEC) {
1807 scp->stime.tv_nsec -= NANOSEC;
1808 scp->stime.tv_sec++;
1812 (void) mutex_unlock(&count_lock);
1813 free(ncp);
1814 break;
1816 default:
1818 abend("Unknown file entry type encountered", NULL);
1819 break;
1823 if (fstat(sfd, &fsi) == -1)
1824 abend("Error stat-ing tempfile", NULL);
1825 filesz = fsi.st_size;
1827 free(s);
1828 free(t);
1831 void
1832 make_pname(private_t *pri, id_t tid)
1834 if (!cflag) {
1835 int ff = (fflag || ngrab > 1);
1836 int lf = (lflag | tid | (Thr_agent != NULL) | (truss_nlwp > 1));
1837 pid_t pid = Pstatus(Proc)->pr_pid;
1838 id_t lwpid = pri->lwpstat->pr_lwpid;
1840 if (ff != pri->pparam.ff ||
1841 lf != pri->pparam.lf ||
1842 pid != pri->pparam.pid ||
1843 lwpid != pri->pparam.lwpid ||
1844 tid != pri->pparam.tid) {
1845 char *s = pri->pname;
1847 if (ff)
1848 s += sprintf(s, "%d", (int)pid);
1849 if (lf)
1850 s += sprintf(s, "/%d", (int)lwpid);
1851 if (tid)
1852 s += sprintf(s, "@%d", (int)tid);
1853 if (ff || lf)
1854 *s++ = ':', *s++ = '\t';
1855 if (ff && lf && s < pri->pname + 9)
1856 *s++ = '\t';
1857 *s = '\0';
1858 pri->pparam.ff = ff;
1859 pri->pparam.lf = lf;
1860 pri->pparam.pid = pid;
1861 pri->pparam.lwpid = lwpid;
1862 pri->pparam.tid = tid;
1868 * Print the pri->pname[] string, if any.
1870 void
1871 putpname(private_t *pri)
1873 if (pri->pname[0])
1874 (void) fputs(pri->pname, stdout);
1878 * Print the timestamp, if requested (-d, -D, or -E).
1880 void
1881 timestamp(private_t *pri)
1883 const lwpstatus_t *Lsp = pri->lwpstat;
1884 int seconds;
1885 int fraction;
1887 if (!(dflag|Dflag|Eflag) || !(Lsp->pr_flags & PR_STOPPED))
1888 return;
1890 seconds = Lsp->pr_tstamp.tv_sec - Cp->basetime.tv_sec;
1891 fraction = Lsp->pr_tstamp.tv_nsec - Cp->basetime.tv_nsec;
1892 if (fraction < 0) {
1893 seconds--;
1894 fraction += NANOSEC;
1896 /* fraction in 1/10 milliseconds, rounded up */
1897 fraction = (fraction + 50000) / 100000;
1898 if (fraction >= (MILLISEC * 10)) {
1899 seconds++;
1900 fraction -= (MILLISEC * 10);
1903 if (dflag) /* time stamp */
1904 (void) printf("%2d.%4.4d\t", seconds, fraction);
1906 if (Dflag) { /* time delta */
1907 int oseconds = pri->seconds;
1908 int ofraction = pri->fraction;
1910 pri->seconds = seconds;
1911 pri->fraction = fraction;
1912 seconds -= oseconds;
1913 fraction -= ofraction;
1914 if (fraction < 0) {
1915 seconds--;
1916 fraction += (MILLISEC * 10);
1918 (void) printf("%2d.%4.4d\t", seconds, fraction);
1921 if (Eflag) {
1922 seconds = Lsp->pr_stime.tv_sec - pri->syslast.tv_sec;
1923 fraction = Lsp->pr_stime.tv_nsec - pri->syslast.tv_nsec;
1925 if (fraction < 0) {
1926 seconds--;
1927 fraction += NANOSEC;
1929 /* fraction in 1/10 milliseconds, rounded up */
1930 fraction = (fraction + 50000) / 100000;
1931 if (fraction >= (MILLISEC * 10)) {
1932 seconds++;
1933 fraction -= (MILLISEC * 10);
1935 (void) printf("%2d.%4.4d\t", seconds, fraction);
1940 * Create output file, being careful about
1941 * suid/sgid and file descriptor 0, 1, 2 issues.
1944 xcreat(char *path)
1946 int fd;
1947 int mode = 0666;
1949 if (Euid == Ruid && Egid == Rgid) /* not set-id */
1950 fd = creat(path, mode);
1951 else if (access(path, F_OK) != 0) { /* file doesn't exist */
1952 /* if directory permissions OK, create file & set ownership */
1954 char *dir;
1955 char *p;
1956 char dot[4];
1958 /* generate path for directory containing file */
1959 if ((p = strrchr(path, '/')) == NULL) { /* no '/' */
1960 p = dir = dot;
1961 *p++ = '.'; /* current directory */
1962 *p = '\0';
1963 } else if (p == path) { /* leading '/' */
1964 p = dir = dot;
1965 *p++ = '/'; /* root directory */
1966 *p = '\0';
1967 } else { /* embedded '/' */
1968 dir = path; /* directory path */
1969 *p = '\0';
1972 if (access(dir, W_OK|X_OK) != 0) {
1973 /* not writeable/searchable */
1974 *p = '/';
1975 fd = -1;
1976 } else { /* create file and set ownership correctly */
1977 *p = '/';
1978 if ((fd = creat(path, mode)) >= 0)
1979 (void) chown(path, (int)Ruid, (int)Rgid);
1981 } else if (access(path, W_OK) != 0) /* file not writeable */
1982 fd = -1;
1983 else
1984 fd = creat(path, mode);
1987 * Make sure it's not one of 0, 1, or 2.
1988 * This allows truss to work when spawned by init(1m).
1990 if (0 <= fd && fd <= 2) {
1991 int dfd = fcntl(fd, F_DUPFD, 3);
1992 (void) close(fd);
1993 fd = dfd;
1997 * Mark it close-on-exec so created processes don't inherit it.
1999 if (fd >= 0)
2000 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
2002 return (fd);
2005 void
2006 setoutput(int ofd)
2008 if (ofd < 0) {
2009 (void) close(1);
2010 (void) fcntl(2, F_DUPFD, 1);
2011 } else if (ofd != 1) {
2012 (void) close(1);
2013 (void) fcntl(ofd, F_DUPFD, 1);
2014 (void) close(ofd);
2015 /* if no stderr, make it the same file */
2016 if ((ofd = dup(2)) < 0)
2017 (void) fcntl(1, F_DUPFD, 2);
2018 else
2019 (void) close(ofd);
2024 * Accumulate time differencies: a += e - s;
2026 void
2027 accumulate(timestruc_t *ap, const timestruc_t *ep, const timestruc_t *sp)
2029 ap->tv_sec += ep->tv_sec - sp->tv_sec;
2030 ap->tv_nsec += ep->tv_nsec - sp->tv_nsec;
2031 if (ap->tv_nsec >= NANOSEC) {
2032 ap->tv_nsec -= NANOSEC;
2033 ap->tv_sec++;
2034 } else if (ap->tv_nsec < 0) {
2035 ap->tv_nsec += NANOSEC;
2036 ap->tv_sec--;
2041 lib_sort(const void *p1, const void *p2)
2043 int cmpr = 0;
2044 long i;
2045 long j;
2047 hentry_t *t1 = (hentry_t *)p1;
2048 hentry_t *t2 = (hentry_t *)p2;
2050 char *p = t1->lib;
2051 char *q = t2->lib;
2053 if ((cmpr = strcmp(p, q)) == 0) {
2054 i = t1->count;
2055 j = t2->count;
2056 if (i > j)
2057 return (-1);
2058 else if (i < j)
2059 return (1);
2060 else {
2061 p = t1->key;
2062 q = t2->key;
2063 return (strcmp(p, q));
2065 } else
2066 return (cmpr);
2069 void
2070 report(private_t *pri, time_t lapse) /* elapsed time, clock ticks */
2072 int i;
2073 long count;
2074 const char *name;
2075 long error;
2076 long total;
2077 long errtot;
2078 timestruc_t tickzero;
2079 timestruc_t ticks;
2080 timestruc_t ticktot;
2082 if (descendent)
2083 return;
2085 for (i = 0, total = 0; i <= PRMAXFAULT && !interrupt; i++) {
2086 if ((count = Cp->fltcount[i]) != 0) {
2087 if (total == 0) /* produce header */
2088 (void) printf("faults -------------\n");
2090 name = proc_fltname(i, pri->flt_name,
2091 sizeof (pri->flt_name));
2093 (void) printf("%s%s\t%4ld\n", name,
2094 (((int)strlen(name) < 8)?
2095 (const char *)"\t" : (const char *)""),
2096 count);
2097 total += count;
2100 if (total && !interrupt)
2101 (void) printf("total:\t\t%4ld\n\n", total);
2103 for (i = 0, total = 0; i <= PRMAXSIG && !interrupt; i++) {
2104 if ((count = Cp->sigcount[i]) != 0) {
2105 if (total == 0) /* produce header */
2106 (void) printf("signals ------------\n");
2107 name = signame(pri, i);
2108 (void) printf("%s%s\t%4ld\n", name,
2109 (((int)strlen(name) < 8)?
2110 (const char *)"\t" : (const char *)""),
2111 count);
2112 total += count;
2115 if (total && !interrupt)
2116 (void) printf("total:\t\t%4ld\n\n", total);
2118 if ((Dynpat != NULL) && !interrupt) {
2119 size_t elem = elements_in_table(fcall_tbl);
2120 hiter_t *itr = iterate_hash(fcall_tbl);
2121 hentry_t *tmp = iter_next(itr);
2122 hentry_t *stbl = my_malloc(elem * sizeof (hentry_t), NULL);
2123 i = 0;
2124 while ((tmp != NULL) && (i < elem)) {
2125 stbl[i].prev = tmp->prev;
2126 stbl[i].next = tmp->next;
2127 stbl[i].lib = tmp->lib;
2128 stbl[i].key = tmp->key;
2129 stbl[i].count = tmp->count;
2130 tmp = iter_next(itr);
2131 i++;
2133 qsort((void *)stbl, elem, sizeof (hentry_t),
2134 lib_sort);
2135 (void) printf(
2136 "\n%-20s %-40s %s\n", "Library:", "Function", "calls");
2137 for (i = 0; i < elem; i++) {
2138 (void) printf("%-20s %-40s %ld\n", stbl[i].lib,
2139 stbl[i].key, stbl[i].count);
2141 iter_free(itr);
2142 free(stbl);
2143 itr = NULL;
2146 if (!interrupt)
2147 (void) printf(
2148 "\nsyscall seconds calls errors\n");
2150 total = errtot = 0;
2151 tickzero.tv_sec = ticks.tv_sec = ticktot.tv_sec = 0;
2152 tickzero.tv_nsec = ticks.tv_nsec = ticktot.tv_nsec = 0;
2153 for (i = 0; i <= PRMAXSYS && !interrupt; i++) {
2154 struct syscount *scp = Cp->syscount[i];
2155 int n = nsubcodes(i);
2156 int subcode;
2158 for (subcode = 0; subcode < n; subcode++, scp++) {
2159 if ((count = scp->count) != 0 || scp->error) {
2160 (void) printf("%-19.19s ",
2161 sysname(pri, i, subcode));
2163 ticks = scp->stime;
2164 accumulate(&ticktot, &ticks, &tickzero);
2165 prtim(&ticks);
2167 (void) printf(" %7ld", count);
2168 if ((error = scp->error) != 0)
2169 (void) printf(" %7ld", error);
2170 (void) fputc('\n', stdout);
2171 total += count;
2172 errtot += error;
2177 if (!interrupt) {
2178 (void) printf(
2179 " -------- ------ ----\n");
2180 (void) printf("sys totals: ");
2181 prtim(&ticktot);
2182 (void) printf(" %7ld %6ld\n", total, errtot);
2185 if (!interrupt) {
2186 (void) printf("usr time: ");
2187 prtim(&Cp->usrtotal);
2188 (void) fputc('\n', stdout);
2191 if (!interrupt) {
2192 int hz = (int)sysconf(_SC_CLK_TCK);
2194 ticks.tv_sec = lapse / hz;
2195 ticks.tv_nsec = (lapse % hz) * (1000000000 / hz);
2196 (void) printf("elapsed: ");
2197 prtim(&ticks);
2198 (void) fputc('\n', stdout);
2202 void
2203 prtim(timestruc_t *tp)
2205 time_t sec;
2207 if ((sec = tp->tv_sec) != 0) /* whole seconds */
2208 (void) printf("%5lu", sec);
2209 else
2210 (void) printf(" ");
2212 (void) printf(".%3.3ld", tp->tv_nsec/1000000); /* fraction */
2216 * Gather process id's.
2217 * Return 0 on success, != 0 on failure.
2219 void
2220 pids(char *arg, proc_set_t *grab)
2222 pid_t pid = -1;
2223 int i;
2224 const char *lwps = NULL;
2226 if ((pid = proc_arg_xpsinfo(arg, PR_ARG_PIDS, NULL, &i, &lwps)) < 0) {
2227 (void) fprintf(stderr, "%s: cannot trace '%s': %s\n",
2228 command, arg, Pgrab_error(i));
2229 return;
2232 for (i = 0; i < ngrab; i++)
2233 if (grab[i].pid == pid) /* duplicate */
2234 break;
2236 if (i == ngrab) {
2237 grab[ngrab].pid = pid;
2238 grab[ngrab].lwps = lwps;
2239 ngrab++;
2240 } else {
2241 (void) fprintf(stderr, "%s: duplicate process-id ignored: %d\n",
2242 command, (int)pid);
2247 * Report psargs string.
2249 void
2250 psargs(private_t *pri)
2252 pid_t pid = Pstatus(Proc)->pr_pid;
2253 psinfo_t psinfo;
2255 if (proc_get_psinfo(pid, &psinfo) == 0)
2256 (void) printf("%spsargs: %.64s\n",
2257 pri->pname, psinfo.pr_psargs);
2258 else {
2259 perror("psargs()");
2260 (void) printf("%s\t*** Cannot read psinfo file for pid %d\n",
2261 pri->pname, (int)pid);
2265 char *
2266 fetchstring(private_t *pri, long addr, int maxleng)
2268 int nbyte;
2269 int leng = 0;
2270 char string[41];
2272 string[40] = '\0';
2273 if (pri->str_bsize == 0) /* initial allocation of string buffer */
2274 pri->str_buffer =
2275 my_malloc(pri->str_bsize = 16, "string buffer");
2276 *pri->str_buffer = '\0';
2278 for (nbyte = 40; nbyte == 40 && leng < maxleng; addr += 40) {
2279 if ((nbyte = Pread(Proc, string, 40, addr)) <= 0)
2280 return (leng? pri->str_buffer : NULL);
2281 if (nbyte > 0 &&
2282 (nbyte = strlen(string)) > 0) {
2283 while (leng + nbyte >= pri->str_bsize)
2284 pri->str_buffer =
2285 my_realloc(pri->str_buffer,
2286 pri->str_bsize *= 2, "string buffer");
2287 (void) strcpy(pri->str_buffer+leng, string);
2288 leng += nbyte;
2292 if (leng > maxleng)
2293 leng = maxleng;
2294 pri->str_buffer[leng] = '\0';
2296 return (pri->str_buffer);
2299 static priv_set_t *
2300 getset(prpriv_t *p, priv_ptype_t set)
2302 return ((priv_set_t *)
2303 &p->pr_sets[priv_getsetbyname(set) * p->pr_setsize]);
2306 void
2307 show_cred(private_t *pri, int new, int loadonly)
2309 prcred_t cred;
2310 prpriv_t *privs;
2312 if (proc_get_cred(Pstatus(Proc)->pr_pid, &cred, 0) < 0) {
2313 perror("show_cred() - credential");
2314 (void) printf("%s\t*** Cannot get credentials\n", pri->pname);
2315 return;
2317 if ((privs = proc_get_priv(Pstatus(Proc)->pr_pid)) == NULL) {
2318 perror("show_cred() - privileges");
2319 (void) printf("%s\t*** Cannot get privileges\n", pri->pname);
2320 return;
2323 if (!loadonly && !cflag && prismember(&trace, SYS_execve)) {
2324 if (new)
2325 credentials = cred;
2326 if ((new && cred.pr_ruid != cred.pr_suid) ||
2327 cred.pr_ruid != credentials.pr_ruid ||
2328 cred.pr_suid != credentials.pr_suid)
2329 (void) printf(
2330 "%s *** SUID: ruid/euid/suid = %d / %d / %d ***\n",
2331 pri->pname,
2332 (int)cred.pr_ruid,
2333 (int)cred.pr_euid,
2334 (int)cred.pr_suid);
2335 if ((new && cred.pr_rgid != cred.pr_sgid) ||
2336 cred.pr_rgid != credentials.pr_rgid ||
2337 cred.pr_sgid != credentials.pr_sgid)
2338 (void) printf(
2339 "%s *** SGID: rgid/egid/sgid = %d / %d / %d ***\n",
2340 pri->pname,
2341 (int)cred.pr_rgid,
2342 (int)cred.pr_egid,
2343 (int)cred.pr_sgid);
2344 if (privdata != NULL && cred.pr_euid != 0) {
2345 priv_set_t *npset = getset(privs, PRIV_PERMITTED);
2346 priv_set_t *opset = getset(privdata, PRIV_PERMITTED);
2347 char *s, *t;
2348 if (!priv_issubset(npset, opset)) {
2349 /* Use the to be freed privdata as scratch */
2350 priv_inverse(opset);
2351 priv_intersect(npset, opset);
2352 s = priv_set_to_str(opset, ',', PRIV_STR_SHORT);
2353 t = priv_set_to_str(npset, ',', PRIV_STR_SHORT);
2354 (void) printf("%s *** FPRIV: P/E: %s ***\n",
2355 pri->pname,
2356 strlen(s) > strlen(t) ? t : s);
2357 free(s);
2358 free(t);
2363 proc_free_priv(privdata);
2364 credentials = cred;
2365 privdata = privs;
2369 * Take control of a child process.
2370 * We come here with truss_lock held.
2373 control(private_t *pri, pid_t pid)
2375 const pstatus_t *Psp;
2376 const lwpstatus_t *Lsp;
2377 pid_t childpid = 0;
2378 long flags;
2379 int rc;
2381 (void) mutex_lock(&gps->fork_lock);
2382 while (gps->fork_pid != 0)
2383 (void) cond_wait(&gps->fork_cv, &gps->fork_lock);
2384 gps->fork_pid = getpid(); /* parent pid */
2385 if ((childpid = fork()) == -1) {
2386 (void) printf("%s\t*** Cannot fork() to control process #%d\n",
2387 pri->pname, (int)pid);
2388 Flush();
2389 gps->fork_pid = 0;
2390 (void) cond_broadcast(&gps->fork_cv);
2391 (void) mutex_unlock(&gps->fork_lock);
2392 release(pri, pid);
2393 return (FALSE);
2396 if (childpid != 0) {
2398 * The parent carries on, after a brief pause.
2399 * The parent must wait until the child executes procadd(pid).
2401 while (gps->fork_pid != childpid)
2402 (void) cond_wait(&gps->fork_cv, &gps->fork_lock);
2403 gps->fork_pid = 0;
2404 (void) cond_broadcast(&gps->fork_cv);
2405 (void) mutex_unlock(&gps->fork_lock);
2406 return (FALSE);
2409 childpid = getpid();
2410 descendent = TRUE;
2411 exit_called = FALSE;
2412 Pfree(Proc); /* forget old process */
2415 * The parent process owns the shared gps->fork_lock.
2416 * The child must grab it again.
2418 (void) mutex_lock(&gps->fork_lock);
2421 * Child grabs the process and retains the tracing flags.
2423 if ((Proc = Pgrab(pid, PGRAB_RETAIN, &rc)) == NULL) {
2424 (void) fprintf(stderr,
2425 "%s: cannot control child process, pid# %d: %s\n",
2426 command, (int)pid, Pgrab_error(rc));
2427 gps->fork_pid = childpid;
2428 (void) cond_broadcast(&gps->fork_cv);
2429 (void) mutex_unlock(&gps->fork_lock);
2430 exit(2);
2433 per_proc_init();
2435 * Add ourself to the set of truss processes
2436 * and notify the parent to carry on.
2438 procadd(pid, NULL);
2439 gps->fork_pid = childpid;
2440 (void) cond_broadcast(&gps->fork_cv);
2441 (void) mutex_unlock(&gps->fork_lock);
2444 * We may have grabbed the child before it is fully stopped on exit
2445 * from fork. Wait one second (at most) for it to settle down.
2447 (void) Pwait(Proc, MILLISEC);
2448 if (Rdb_agent != NULL)
2449 Rdb_agent = Prd_agent(Proc);
2451 Psp = Pstatus(Proc);
2452 Lsp = &Psp->pr_lwp;
2453 pri->lwpstat = Lsp;
2454 data_model = Psp->pr_dmodel;
2456 make_pname(pri, 0);
2458 pri->syslast = Psp->pr_stime;
2459 pri->usrlast = Psp->pr_utime;
2461 flags = PR_FORK | PR_ASYNC;
2462 if (Dynpat != NULL)
2463 flags |= PR_BPTADJ; /* needed for x86 */
2464 (void) Psetflags(Proc, flags);
2466 return (TRUE);
2470 * Take control of an existing process.
2473 grabit(private_t *pri, proc_set_t *set)
2475 const pstatus_t *Psp;
2476 const lwpstatus_t *Lsp;
2477 int gcode;
2480 * Don't force the takeover unless the -F option was specified.
2482 if ((Proc = Pgrab(set->pid, Fflag, &gcode)) == NULL) {
2483 (void) fprintf(stderr, "%s: %s: %d\n",
2484 command, Pgrab_error(gcode), (int)set->pid);
2485 pri->lwpstat = NULL;
2486 return (FALSE);
2488 Psp = Pstatus(Proc);
2489 Lsp = &Psp->pr_lwp;
2490 pri->lwpstat = Lsp;
2492 make_pname(pri, 0);
2494 data_model = Psp->pr_dmodel;
2495 pri->syslast = Psp->pr_stime;
2496 pri->usrlast = Psp->pr_utime;
2498 if (fflag || Dynpat != NULL)
2499 (void) Psetflags(Proc, PR_FORK);
2500 else
2501 (void) Punsetflags(Proc, PR_FORK);
2502 procadd(set->pid, set->lwps);
2503 show_cred(pri, TRUE, FALSE);
2504 return (TRUE);
2508 * Release process from control.
2510 void
2511 release(private_t *pri, pid_t pid)
2514 * The process in question is the child of a traced process.
2515 * We are here to turn off the inherited tracing flags.
2517 int fd;
2518 char ctlname[100];
2519 long ctl[2];
2521 ctl[0] = PCSET;
2522 ctl[1] = PR_RLC;
2524 /* process is freshly forked, no need for exclusive open */
2525 (void) sprintf(ctlname, "/proc/%d/ctl", (int)pid);
2526 if ((fd = open(ctlname, O_WRONLY)) < 0 ||
2527 write(fd, (char *)ctl, sizeof (ctl)) < 0) {
2528 perror("release()");
2529 (void) printf(
2530 "%s\t*** Cannot release child process, pid# %d\n",
2531 pri->pname, (int)pid);
2532 Flush();
2534 if (fd >= 0) /* run-on-last-close sets the process running */
2535 (void) close(fd);
2538 void
2539 intr(int sig)
2542 * SIGUSR1 is special. It is used by one truss process to tell
2543 * another truss process to release its controlled process.
2544 * SIGUSR2 is also special. It is used to wake up threads waiting
2545 * for a victim lwp to stop after an event that will leave the
2546 * process hung (stopped and abandoned) has occurred.
2548 if (sig == SIGUSR1) {
2549 sigusr1 = TRUE;
2550 } else if (sig == SIGUSR2) {
2551 void *value;
2552 private_t *pri;
2553 struct ps_lwphandle *Lwp;
2555 if (thr_getspecific(private_key, &value) == 0 &&
2556 (pri = value) != NULL &&
2557 (Lwp = pri->Lwp) != NULL)
2558 (void) Lstop(Lwp, MILLISEC / 10);
2559 } else {
2560 interrupt = sig;
2564 void
2565 errmsg(const char *s, const char *q)
2567 char msg[512];
2569 if (s || q) {
2570 msg[0] = '\0';
2571 if (command) {
2572 (void) strcpy(msg, command);
2573 (void) strcat(msg, ": ");
2575 if (s)
2576 (void) strcat(msg, s);
2577 if (q)
2578 (void) strcat(msg, q);
2579 (void) strcat(msg, "\n");
2580 (void) write(2, msg, (size_t)strlen(msg));
2584 void
2585 abend(const char *s, const char *q)
2587 (void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL);
2588 if (Proc) {
2589 Flush();
2590 errmsg(s, q);
2591 clear_breakpoints();
2592 (void) Punsetflags(Proc, PR_ASYNC);
2593 Prelease(Proc, created? PRELEASE_KILL : PRELEASE_CLEAR);
2594 procdel();
2595 (void) wait4all();
2596 } else {
2597 errmsg(s, q);
2599 exit(2);
2603 * Allocate memory.
2604 * If allocation fails then print a message and abort.
2606 void *
2607 my_realloc(void *buf, size_t size, const char *msg)
2609 if ((buf = realloc(buf, size)) == NULL) {
2610 if (msg != NULL)
2611 abend("cannot allocate ", msg);
2612 else
2613 abend("memory allocation failure", NULL);
2616 return (buf);
2619 void *
2620 my_calloc(size_t nelem, size_t elsize, const char *msg)
2622 void *buf = NULL;
2624 if ((buf = calloc(nelem, elsize)) == NULL) {
2625 if (msg != NULL)
2626 abend("cannot allocate ", msg);
2627 else
2628 abend("memory allocation failure", NULL);
2631 return (buf);
2634 void *
2635 my_malloc(size_t size, const char *msg)
2637 return (my_realloc(NULL, size, msg));
2641 wait4all()
2643 int i;
2644 pid_t pid;
2645 int rc = 0;
2646 int status;
2648 for (i = 0; i < 10; i++) {
2649 while ((pid = wait(&status)) != -1) {
2650 /* return exit() code of the created process */
2651 if (pid == created) {
2652 if (WIFEXITED(status))
2653 rc = WEXITSTATUS(status);
2654 else
2655 rc |= 0x80; /* +128 to indicate sig */
2658 if (errno != EINTR && errno != ERESTART)
2659 break;
2662 if (i >= 10) /* repeated interrupts */
2663 rc = 2;
2665 return (rc);
2668 void
2669 letgo(private_t *pri)
2671 (void) printf("%s\t*** process otherwise traced, releasing ...\n",
2672 pri->pname);
2676 * Test for empty set.
2677 * support routine used by isemptyset() macro.
2680 is_empty(const uint32_t *sp, /* pointer to set (array of int32's) */
2681 size_t n) /* number of int32's in set */
2683 if (n) {
2684 do {
2685 if (*sp++)
2686 return (FALSE);
2687 } while (--n);
2690 return (TRUE);
2694 * OR the second set into the first.
2695 * The sets must be the same size.
2697 void
2698 or_set(uint32_t *sp1, const uint32_t *sp2, size_t n)
2700 if (n) {
2701 do {
2702 *sp1++ |= *sp2++;
2703 } while (--n);