8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / truss / main.c
blob23c2056314fd6498754d630f7568ed36c1316807
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 if (pri->sys_path)
134 free(pri->sys_path);
135 if (pri->sys_string)
136 free(pri->sys_string);
137 if (pri->exec_string)
138 free(pri->exec_string);
139 if (pri->str_buffer)
140 free(pri->str_buffer);
141 free(pri);
145 * This is called by the main thread (via create_thread())
146 * and is also called from other threads in worker_thread()
147 * while holding truss_lock. No further locking is required.
149 void
150 insert_lwpid(lwpid_t lwpid)
152 int i;
154 truss_nlwp++;
155 for (i = 0; i < truss_maxlwp; i++) {
156 if (truss_lwpid[i] == 0)
157 break;
159 if (i == truss_maxlwp) {
160 /* double the size of the array */
161 truss_lwpid = my_realloc(truss_lwpid,
162 truss_maxlwp * 2 * sizeof (lwpid_t), NULL);
163 (void) memset(&truss_lwpid[truss_maxlwp], 0,
164 truss_maxlwp * sizeof (lwpid_t));
165 truss_maxlwp *= 2;
167 truss_lwpid[i] = lwpid;
171 * This is called from the first worker thread to encounter one of
172 * (leave_hung || interrupt || sigusr1). It must notify all other
173 * worker threads of the same condition. truss_lock is held.
175 void
176 broadcast_signals(void)
178 static int int_notified = FALSE;
179 static int usr1_notified = FALSE;
180 static int usr2_notified = FALSE;
181 lwpid_t my_id = thr_self();
182 lwpid_t lwpid;
183 int i;
185 if (interrupt && !int_notified) {
186 int_notified = TRUE;
187 for (i = 0; i < truss_maxlwp; i++) {
188 if ((lwpid = truss_lwpid[i]) != 0 && lwpid != my_id)
189 (void) thr_kill(lwpid, interrupt);
192 if (sigusr1 && !usr1_notified) {
193 usr1_notified = TRUE;
194 for (i = 0; i < truss_maxlwp; i++) {
195 if ((lwpid = truss_lwpid[i]) != 0 && lwpid != my_id)
196 (void) thr_kill(lwpid, SIGUSR1);
199 if (leave_hung && !usr2_notified) {
200 usr2_notified = TRUE;
201 for (i = 0; i < truss_maxlwp; i++) {
202 if ((lwpid = truss_lwpid[i]) != 0 && lwpid != my_id)
203 (void) thr_kill(lwpid, SIGUSR2);
208 static struct ps_lwphandle *
209 grab_lwp(lwpid_t who)
211 struct ps_lwphandle *Lwp;
212 int gcode;
214 if ((Lwp = Lgrab(Proc, who, &gcode)) == NULL) {
215 if (gcode != G_NOPROC) {
216 (void) fprintf(stderr,
217 "%s: cannot grab LWP %u in process %d,"
218 " reason: %s\n",
219 command, who, (int)Pstatus(Proc)->pr_pid,
220 Lgrab_error(gcode));
221 interrupt = SIGTERM; /* post an interrupt */
224 return (Lwp);
228 * Iteration function called for each initial lwp in the controlled process.
230 /* ARGSUSED */
232 create_thread(void *arg, const lwpstatus_t *Lsp)
234 struct ps_lwphandle *new_Lwp;
235 lwpid_t lwpid;
236 int *count = arg;
238 if (lwptrace(Pstatus(Proc)->pr_pid, Lsp->pr_lwpid))
239 *count += 1;
241 if ((new_Lwp = grab_lwp(Lsp->pr_lwpid)) != NULL) {
242 if (thr_create(NULL, 0, worker_thread, new_Lwp,
243 THR_BOUND | THR_SUSPENDED, &lwpid) != 0)
244 abend("cannot create lwp to follow child lwp", NULL);
245 insert_lwpid(lwpid);
247 return (0);
251 main(int argc, char *argv[])
253 private_t *pri;
254 struct tms tms;
255 struct rlimit rlim;
256 int ofd = -1;
257 int opt;
258 int i;
259 int first;
260 int errflg = FALSE;
261 int badname = FALSE;
262 proc_set_t *grab = NULL;
263 const pstatus_t *Psp;
264 const lwpstatus_t *Lsp;
265 int sharedmem;
267 /* a few of these need to be initialized to NULL */
268 Cp = NULL;
269 fcall_tbl = NULL;
272 * Make sure fd's 0, 1, and 2 are allocated,
273 * just in case truss was invoked from init.
275 while ((i = open("/dev/null", O_RDWR)) >= 0 && i < 2)
277 if (i > 2)
278 (void) close(i);
280 starttime = times(&tms); /* for elapsed timing */
282 /* this should be per-traced-process */
283 pagesize = sysconf(_SC_PAGESIZE);
285 /* command name (e.g., "truss") */
286 if ((command = strrchr(argv[0], '/')) != NULL)
287 command++;
288 else
289 command = argv[0];
291 /* set up the initial private data */
292 (void) mutex_init(&truss_lock, USYNC_THREAD, NULL);
293 (void) mutex_init(&count_lock, USYNC_THREAD, NULL);
294 (void) cond_init(&truss_cv, USYNC_THREAD, NULL);
295 if (thr_keycreate(&private_key, free_private) == ENOMEM)
296 abend("memory allocation failure", NULL);
297 pri = get_private();
299 Euid = geteuid();
300 Egid = getegid();
301 Ruid = getuid();
302 Rgid = getgid();
303 ancestor = getpid();
305 prfillset(&trace); /* default: trace all system calls */
306 premptyset(&verbose); /* default: no syscall verbosity */
307 premptyset(&rawout); /* default: no raw syscall interpretation */
309 prfillset(&signals); /* default: trace all signals */
311 prfillset(&faults); /* default: trace all faults */
312 prdelset(&faults, FLTPAGE); /* except this one */
314 premptyset(&readfd); /* default: dump no buffers */
315 premptyset(&writefd);
317 premptyset(&syshang); /* default: hang on no system calls */
318 premptyset(&sighang); /* default: hang on no signals */
319 premptyset(&flthang); /* default: hang on no faults */
321 (void) sigemptyset(&emptyset); /* for unblocking all signals */
322 (void) sigfillset(&fillset); /* for blocking all signals */
324 #define OPTIONS "FpfcaeildDEht:T:v:x:s:S:m:M:u:U:r:w:o:"
325 while ((opt = getopt(argc, argv, OPTIONS)) != EOF) {
326 switch (opt) {
327 case 'F': /* force grabbing (no O_EXCL) */
328 Fflag = PGRAB_FORCE;
329 break;
330 case 'p': /* grab processes */
331 pflag = TRUE;
332 break;
333 case 'f': /* follow children */
334 fflag = TRUE;
335 break;
336 case 'c': /* don't trace, just count */
337 cflag = TRUE;
338 iflag = TRUE; /* implies no interruptable syscalls */
339 break;
340 case 'a': /* display argument lists */
341 aflag = TRUE;
342 break;
343 case 'e': /* display environments */
344 eflag = TRUE;
345 break;
346 case 'i': /* don't show interruptable syscalls */
347 iflag = TRUE;
348 break;
349 case 'l': /* show lwp id for each syscall */
350 lflag = TRUE;
351 break;
352 case 'h': /* debugging: report hash stats */
353 hflag = TRUE;
354 break;
355 case 'd': /* show time stamps */
356 dflag = TRUE;
357 break;
358 case 'D': /* show time deltas */
359 Dflag = TRUE;
360 break;
361 case 'E':
362 Eflag = TRUE; /* show syscall times */
363 break;
364 case 't': /* system calls to trace */
365 if (syslist(optarg, &trace, &tflag))
366 badname = TRUE;
367 break;
368 case 'T': /* system calls to hang process */
369 if (syslist(optarg, &syshang, &Tflag))
370 badname = TRUE;
371 break;
372 case 'v': /* verbose interpretation of syscalls */
373 if (syslist(optarg, &verbose, &vflag))
374 badname = TRUE;
375 break;
376 case 'x': /* raw interpretation of syscalls */
377 if (syslist(optarg, &rawout, &xflag))
378 badname = TRUE;
379 break;
380 case 's': /* signals to trace */
381 if (siglist(pri, optarg, &signals, &sflag))
382 badname = TRUE;
383 break;
384 case 'S': /* signals to hang process */
385 if (siglist(pri, optarg, &sighang, &Sflag))
386 badname = TRUE;
387 break;
388 case 'm': /* machine faults to trace */
389 if (fltlist(optarg, &faults, &mflag))
390 badname = TRUE;
391 break;
392 case 'M': /* machine faults to hang process */
393 if (fltlist(optarg, &flthang, &Mflag))
394 badname = TRUE;
395 break;
396 case 'u': /* user library functions to trace */
397 if (liblist(optarg, 0))
398 badname = TRUE;
399 break;
400 case 'U': /* user library functions to hang */
401 if (liblist(optarg, 1))
402 badname = TRUE;
403 break;
404 case 'r': /* show contents of read(fd) */
405 if (fdlist(optarg, &readfd))
406 badname = TRUE;
407 break;
408 case 'w': /* show contents of write(fd) */
409 if (fdlist(optarg, &writefd))
410 badname = TRUE;
411 break;
412 case 'o': /* output file for trace */
413 oflag = TRUE;
414 if (ofd >= 0)
415 (void) close(ofd);
416 if ((ofd = xcreat(optarg)) < 0) {
417 perror(optarg);
418 badname = TRUE;
420 break;
421 default:
422 errflg = TRUE;
423 break;
427 if (badname)
428 exit(2);
430 /* if -a or -e was specified, force tracing of exec() */
431 if (aflag || eflag)
432 praddset(&trace, SYS_execve);
435 * Make sure that all system calls, signals, and machine faults
436 * that hang the process are added to their trace sets.
438 prorset(&trace, &syshang);
439 prorset(&signals, &sighang);
440 prorset(&faults, &flthang);
442 argc -= optind;
443 argv += optind;
445 /* collect the specified process ids */
446 if (pflag && argc > 0) {
447 grab = my_malloc(argc * sizeof (proc_set_t),
448 "memory for process-ids");
449 while (argc-- > 0)
450 pids(*argv++, grab);
453 if (errflg || (argc <= 0 && ngrab <= 0)) {
454 (void) fprintf(stderr,
455 "usage:\t%s [-fcaeildDEF] [-[tTvx] [!]syscalls] [-[sS] [!]signals]\\\n",
456 command);
457 (void) fprintf(stderr,
458 "\t[-[mM] [!]faults] [-[rw] [!]fds] [-[uU] [!]libs:[:][!]funcs]\\\n");
459 (void) fprintf(stderr,
460 "\t[-o outfile] command | -p pid[/lwps] ...\n");
461 exit(2);
464 if (argc > 0) { /* create the controlled process */
465 int err;
466 char path[PATH_MAX];
468 Proc = Pcreate(argv[0], &argv[0], &err, path, sizeof (path));
469 if (Proc == NULL) {
470 switch (err) {
471 case C_PERM:
472 (void) fprintf(stderr,
473 "%s: cannot trace set-id or "
474 "unreadable object file: %s\n",
475 command, path);
476 break;
477 case C_LP64:
478 (void) fprintf(stderr,
479 "%s: cannot control _LP64 "
480 "program: %s\n",
481 command, path);
482 break;
483 case C_NOEXEC:
484 (void) fprintf(stderr,
485 "%s: cannot execute program: %s\n",
486 command, argv[0]);
487 break;
488 case C_NOENT:
489 (void) fprintf(stderr,
490 "%s: cannot find program: %s\n",
491 command, argv[0]);
492 break;
493 case C_STRANGE:
494 break;
495 default:
496 (void) fprintf(stderr, "%s: %s\n",
497 command, Pcreate_error(err));
498 break;
500 exit(2);
502 if (fflag || Dynpat != NULL)
503 (void) Psetflags(Proc, PR_FORK);
504 else
505 (void) Punsetflags(Proc, PR_FORK);
506 Psp = Pstatus(Proc);
507 Lsp = &Psp->pr_lwp;
508 pri->lwpstat = Lsp;
509 data_model = Psp->pr_dmodel;
510 created = Psp->pr_pid;
511 make_pname(pri, 0);
512 (void) sysentry(pri, 1);
513 pri->length = 0;
514 if (!cflag && prismember(&trace, SYS_execve)) {
515 pri->exec_string = my_realloc(pri->exec_string,
516 strlen(pri->sys_string) + 1, NULL);
517 (void) strcpy(pri->exec_pname, pri->pname);
518 (void) strcpy(pri->exec_string, pri->sys_string);
519 pri->length += strlen(pri->sys_string);
520 pri->exec_lwpid = pri->lwpstat->pr_lwpid;
521 pri->sys_leng = 0;
522 *pri->sys_string = '\0';
524 pri->syslast = Psp->pr_stime;
525 pri->usrlast = Psp->pr_utime;
529 * Now that we have created the victim process,
530 * give ourself a million file descriptors.
531 * This is enough to deal with a multithreaded
532 * victim process that has half a million lwps.
534 rlim.rlim_cur = 1024 * 1024;
535 rlim.rlim_max = 1024 * 1024;
536 if ((Euid != 0 || setrlimit(RLIMIT_NOFILE, &rlim) != 0) &&
537 getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
539 * Failing the million, give ourself as many
540 * file descriptors as we can get.
542 rlim.rlim_cur = rlim.rlim_max;
543 (void) setrlimit(RLIMIT_NOFILE, &rlim);
545 (void) enable_extended_FILE_stdio(-1, -1);
547 setoutput(ofd); /* establish truss output */
548 istty = isatty(1);
550 if (setvbuf(stdout, (char *)NULL, _IOFBF, MYBUFSIZ) != 0)
551 abend("setvbuf() failure", NULL);
554 * Set up signal dispositions.
556 if (created && (oflag || !istty)) { /* ignore interrupts */
557 (void) sigset(SIGHUP, SIG_IGN);
558 (void) sigset(SIGINT, SIG_IGN);
559 (void) sigset(SIGQUIT, SIG_IGN);
560 } else { /* receive interrupts */
561 if (sigset(SIGHUP, SIG_IGN) == SIG_DFL)
562 (void) sigset(SIGHUP, intr);
563 if (sigset(SIGINT, SIG_IGN) == SIG_DFL)
564 (void) sigset(SIGINT, intr);
565 if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL)
566 (void) sigset(SIGQUIT, intr);
568 (void) sigset(SIGTERM, intr);
569 (void) sigset(SIGUSR1, intr);
570 (void) sigset(SIGUSR2, intr);
571 (void) sigset(SIGPIPE, intr);
573 /* don't accumulate zombie children */
574 (void) sigset(SIGCLD, SIG_IGN);
576 /* create shared mem space for global mutexes */
578 sharedmem = (fflag || Dynpat != NULL || ngrab > 1);
579 gps = (void *)mmap(NULL, sizeof (struct global_psinfo),
580 PROT_READ|PROT_WRITE,
581 MAP_ANON | (sharedmem? MAP_SHARED : MAP_PRIVATE),
582 -1, (off_t)0);
583 if (gps == MAP_FAILED)
584 abend("cannot allocate ", "memory for counts");
585 i = sharedmem? USYNC_PROCESS : USYNC_THREAD;
586 (void) mutex_init(&gps->ps_mutex0, i, NULL);
587 (void) mutex_init(&gps->ps_mutex1, i, NULL);
588 (void) mutex_init(&gps->fork_lock, i, NULL);
589 (void) cond_init(&gps->fork_cv, i, NULL);
592 /* config tmp file if counting and following */
593 if (fflag && cflag) {
594 char *tmps = tempnam("/var/tmp", "truss");
595 sfd = open(tmps, O_CREAT|O_APPEND|O_EXCL|O_RDWR, 0600);
596 if (sfd == -1)
597 abend("Error creating tmpfile", NULL);
598 if (unlink(tmps) == -1)
599 abend("Error unlinking tmpfile", NULL);
600 free(tmps);
601 tmps = NULL;
604 if (created) {
605 per_proc_init();
606 procadd(created, NULL);
607 show_cred(pri, TRUE, FALSE);
608 } else { /* grab the specified processes */
609 int gotone = FALSE;
611 i = 0;
612 while (i < ngrab) { /* grab first process */
613 if (grabit(pri, &grab[i++])) {
614 Psp = Pstatus(Proc);
615 Lsp = &Psp->pr_lwp;
616 gotone = TRUE;
617 break;
620 if (!gotone)
621 abend(NULL, NULL);
622 per_proc_init();
623 while (i < ngrab) { /* grab the remainder */
624 proc_set_t *set = &grab[i++];
626 (void) mutex_lock(&truss_lock);
627 switch (fork()) {
628 case -1:
629 (void) fprintf(stderr,
630 "%s: cannot fork to control process, pid# %d\n",
631 command, (int)set->pid);
632 /* FALLTHROUGH */
633 default:
634 (void) mutex_unlock(&truss_lock);
635 continue; /* parent carries on */
637 case 0: /* child grabs process */
638 (void) mutex_unlock(&truss_lock);
639 Pfree(Proc);
640 descendent = TRUE;
641 if (grabit(pri, set)) {
642 Psp = Pstatus(Proc);
643 Lsp = &Psp->pr_lwp;
644 per_proc_init();
645 break;
647 exit(2);
649 break;
651 free(grab);
656 * If running setuid-root, become root for real to avoid
657 * affecting the per-user limitation on the maximum number
658 * of processes (one benefit of running setuid-root).
660 if (Rgid != Egid)
661 (void) setgid(Egid);
662 if (Ruid != Euid)
663 (void) setuid(Euid);
665 if (!created && aflag && prismember(&trace, SYS_execve)) {
666 psargs(pri);
667 Flush();
670 if (created && Pstate(Proc) != PS_STOP) /* assertion */
671 if (!(interrupt | sigusr1))
672 abend("ASSERT error: process is not stopped", NULL);
674 traceeven = trace; /* trace these system calls */
676 /* trace these regardless, even if we don't report results */
677 praddset(&traceeven, SYS_exit);
678 praddset(&traceeven, SYS_lwp_create);
679 praddset(&traceeven, SYS_lwp_exit);
680 praddset(&traceeven, SYS_execve);
681 praddset(&traceeven, SYS_openat);
682 praddset(&traceeven, SYS_openat64);
683 praddset(&traceeven, SYS_open);
684 praddset(&traceeven, SYS_open64);
685 praddset(&traceeven, SYS_vfork);
686 praddset(&traceeven, SYS_forksys);
688 /* for I/O buffer dumps, force tracing of read()s and write()s */
689 if (!isemptyset(&readfd)) {
690 praddset(&traceeven, SYS_read);
691 praddset(&traceeven, SYS_readv);
692 praddset(&traceeven, SYS_pread);
693 praddset(&traceeven, SYS_pread64);
694 praddset(&traceeven, SYS_recv);
695 praddset(&traceeven, SYS_recvfrom);
696 praddset(&traceeven, SYS_recvmsg);
698 if (!isemptyset(&writefd)) {
699 praddset(&traceeven, SYS_write);
700 praddset(&traceeven, SYS_writev);
701 praddset(&traceeven, SYS_pwrite);
702 praddset(&traceeven, SYS_pwrite64);
703 praddset(&traceeven, SYS_send);
704 praddset(&traceeven, SYS_sendto);
705 praddset(&traceeven, SYS_sendmsg);
708 if (cflag || Eflag) {
709 Psetsysentry(Proc, &traceeven);
711 Psetsysexit(Proc, &traceeven);
713 /* special case -- cannot trace sysexit because context is changed */
714 if (prismember(&trace, SYS_context)) {
715 (void) Psysentry(Proc, SYS_context, TRUE);
716 (void) Psysexit(Proc, SYS_context, FALSE);
717 prdelset(&traceeven, SYS_context);
720 /* special case -- trace exec() on entry to get the args */
721 (void) Psysentry(Proc, SYS_execve, TRUE);
723 /* special case -- sysexit never reached */
724 (void) Psysentry(Proc, SYS_exit, TRUE);
725 (void) Psysentry(Proc, SYS_lwp_exit, TRUE);
726 (void) Psysexit(Proc, SYS_exit, FALSE);
727 (void) Psysexit(Proc, SYS_lwp_exit, FALSE);
729 Psetsignal(Proc, &signals); /* trace these signals */
730 Psetfault(Proc, &faults); /* trace these faults */
732 /* for function call tracing */
733 if (Dynpat != NULL) {
734 /* trace these regardless, to deal with function calls */
735 (void) Pfault(Proc, FLTBPT, TRUE);
736 (void) Pfault(Proc, FLTTRACE, TRUE);
738 /* needed for x86 */
739 (void) Psetflags(Proc, PR_BPTADJ);
742 * Find functions and set breakpoints on grabbed process.
743 * A process stopped on exec() gets its breakpoints set below.
745 if ((Lsp->pr_why != PR_SYSENTRY &&
746 Lsp->pr_why != PR_SYSEXIT) ||
747 Lsp->pr_what != SYS_execve) {
748 establish_breakpoints();
749 establish_stacks();
754 * Use asynchronous-stop for multithreaded truss.
755 * truss runs one lwp for each lwp in the target process.
757 (void) Psetflags(Proc, PR_ASYNC);
759 /* flush out all tracing flags now. */
760 Psync(Proc);
763 * If we grabbed a running process, set it running again.
764 * Since we are tracing lwp_create() and lwp_exit(), the
765 * lwps will not change in the process until we create all
766 * of the truss worker threads.
767 * We leave a created process stopped so its exec() can be reported.
769 first = created? FALSE : TRUE;
770 if (!created &&
771 ((Pstate(Proc) == PS_STOP && Lsp->pr_why == PR_REQUESTED) ||
772 (Lsp->pr_flags & PR_DSTOP)))
773 first = FALSE;
775 main_thread(first);
776 return (0);
780 * Called from main() and from control() after fork().
782 void
783 main_thread(int first)
785 private_t *pri = get_private();
786 struct tms tms;
787 int flags;
788 int retc;
789 int i;
790 int count;
793 * Block all signals in the main thread.
794 * Some worker thread will receive signals.
796 (void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL);
799 * If we are dealing with a previously hung process,
800 * arrange not to leave it hung on the same system call.
802 primary_lwp = (first && Pstate(Proc) == PS_STOP)?
803 Pstatus(Proc)->pr_lwp.pr_lwpid : 0;
806 * Create worker threads to match the lwps in the target process.
808 truss_nlwp = 0;
809 truss_maxlwp = 1;
810 truss_lwpid = my_realloc(truss_lwpid, sizeof (lwpid_t), NULL);
811 truss_lwpid[0] = 0;
812 count = 0;
813 (void) Plwp_iter(Proc, create_thread, &count);
815 if (count == 0) {
816 (void) printf("(Warning: no matching active LWPs found, "
817 "waiting)\n");
818 Flush();
822 * Set all of the truss worker threads running now.
824 (void) mutex_lock(&truss_lock);
825 for (i = 0; i < truss_maxlwp; i++) {
826 if (truss_lwpid[i])
827 (void) thr_continue(truss_lwpid[i]);
829 (void) mutex_unlock(&truss_lock);
832 * Wait until all worker threads terminate.
834 while (thr_join(0, NULL, NULL) == 0)
835 continue;
837 (void) Punsetflags(Proc, PR_ASYNC);
838 Psync(Proc);
839 if (sigusr1)
840 letgo(pri);
841 flags = PRELEASE_CLEAR;
842 if (leave_hung)
843 flags |= PRELEASE_HANG;
844 Prelease(Proc, flags);
846 procdel();
847 retc = (leave_hung? 0 : wait4all());
849 if (!descendent) {
850 interrupt = 0; /* another interrupt kills the report */
851 if (cflag) {
852 if (fflag)
853 file_to_parent();
854 report(pri, times(&tms) - starttime);
856 } else if (cflag && fflag) {
857 child_to_file();
860 exit(retc); /* exit with exit status of created process, else 0 */
863 void *
864 worker_thread(void *arg)
866 struct ps_lwphandle *Lwp = (struct ps_lwphandle *)arg;
867 const pstatus_t *Psp = Pstatus(Proc);
868 const lwpstatus_t *Lsp = Lstatus(Lwp);
869 struct syscount *scp;
870 lwpid_t who = Lsp->pr_lwpid;
871 int first = (who == primary_lwp);
872 private_t *pri = get_private();
873 int req_flag = 0;
874 int leave_it_hung = FALSE;
875 int reset_traps = FALSE;
876 int gcode;
877 int what;
878 int ow_in_effect = 0;
879 long ow_syscall = 0;
880 long ow_subcode = 0;
881 char *ow_string = NULL;
882 sysset_t full_set;
883 sysset_t running_set;
884 int dotrace = lwptrace(Psp->pr_pid, Lsp->pr_lwpid);
886 pri->Lwp = Lwp;
887 pri->lwpstat = Lsp;
888 pri->syslast = Lsp->pr_stime;
889 pri->usrlast = Lsp->pr_utime;
890 make_pname(pri, 0);
892 prfillset(&full_set);
894 /* we were created with all signals blocked; unblock them */
895 (void) thr_sigsetmask(SIG_SETMASK, &emptyset, NULL);
898 * Run this loop until the victim lwp terminates or we receive
899 * a termination condition (leave_hung | interrupt | sigusr1).
901 for (;;) {
902 if (interrupt | sigusr1) {
903 (void) Lstop(Lwp, MILLISEC);
904 if (Lstate(Lwp) == PS_RUN)
905 break;
907 if (Lstate(Lwp) == PS_RUN) {
908 /* millisecond timeout is for sleeping syscalls */
909 uint_t tout = (iflag || req_flag)? 0 : MILLISEC;
912 * If we are to leave this lwp stopped in sympathy
913 * with another lwp that has been left hung, or if
914 * we have been interrupted or instructed to release
915 * our victim process, and this lwp is stopped but
916 * not on an event of interest to /proc, then just
917 * leave it in that state.
919 if ((leave_hung | interrupt | sigusr1) &&
920 (Lsp->pr_flags & (PR_STOPPED|PR_ISTOP))
921 == PR_STOPPED)
922 break;
924 (void) Lwait(Lwp, tout);
925 if (Lstate(Lwp) == PS_RUN &&
926 tout != 0 && !(interrupt | sigusr1)) {
927 (void) mutex_lock(&truss_lock);
928 if ((Lsp->pr_flags & PR_STOPPED) &&
929 Lsp->pr_why == PR_JOBCONTROL)
930 req_flag = jobcontrol(pri, dotrace);
931 else
932 req_flag = requested(pri, req_flag,
933 dotrace);
934 (void) mutex_unlock(&truss_lock);
936 continue;
938 data_model = Psp->pr_dmodel;
939 if (Lstate(Lwp) == PS_UNDEAD)
940 break;
941 if (Lstate(Lwp) == PS_LOST) { /* we lost control */
943 * After exec(), only one LWP remains in the process.
944 * /proc makes the thread following that LWP receive
945 * EAGAIN (PS_LOST) if the program being exec()ed
946 * is a set-id program. Every other controlling
947 * thread receives ENOENT (because its LWP vanished).
948 * We are the controlling thread for the exec()ing LWP.
949 * We must wait until all of our siblings terminate
950 * before attempting to reopen the process.
952 (void) mutex_lock(&truss_lock);
953 while (truss_nlwp > 1)
954 (void) cond_wait(&truss_cv, &truss_lock);
955 if (Preopen(Proc) == 0) { /* we got control back */
957 * We have to free and re-grab the LWP.
958 * The process is guaranteed to be at exit
959 * from exec() or execve() and have only
960 * one LWP, namely this one, and the LWP
961 * is guaranteed to have lwpid == 1.
962 * This "cannot fail".
964 who = 1;
965 Lfree(Lwp);
966 pri->Lwp = Lwp =
967 Lgrab(Proc, who, &gcode);
968 if (Lwp == NULL)
969 abend("Lgrab error: ",
970 Lgrab_error(gcode));
971 pri->lwpstat = Lsp = Lstatus(Lwp);
972 (void) mutex_unlock(&truss_lock);
973 continue;
976 /* we really lost it */
977 if (pri->exec_string && *pri->exec_string) {
978 if (pri->exec_pname[0] != '\0')
979 (void) fputs(pri->exec_pname, stdout);
980 timestamp(pri);
981 (void) fputs(pri->exec_string, stdout);
982 (void) fputc('\n', stdout);
983 } else if (pri->length) {
984 (void) fputc('\n', stdout);
986 if (pri->sys_valid)
987 (void) printf(
988 "%s\t*** cannot trace across exec() of %s ***\n",
989 pri->pname, pri->sys_path);
990 else
991 (void) printf(
992 "%s\t*** lost control of process ***\n",
993 pri->pname);
994 pri->length = 0;
995 Flush();
996 (void) mutex_unlock(&truss_lock);
997 break;
999 if (Lstate(Lwp) != PS_STOP) {
1000 (void) fprintf(stderr,
1001 "%s: state = %d\n", command, Lstate(Lwp));
1002 abend(pri->pname, "uncaught status of subject lwp");
1005 make_pname(pri, 0);
1007 (void) mutex_lock(&truss_lock);
1009 what = Lsp->pr_what;
1010 req_flag = 0;
1012 switch (Lsp->pr_why) {
1013 case PR_REQUESTED:
1014 break;
1015 case PR_SIGNALLED:
1016 req_flag = signalled(pri, req_flag, dotrace);
1017 if (Sflag && !first && prismember(&sighang, what))
1018 leave_it_hung = TRUE;
1019 break;
1020 case PR_FAULTED:
1021 if (what == FLTBPT) {
1022 int rval;
1024 (void) Pstop(Proc, 0);
1025 rval = function_trace(pri, first, 0, dotrace);
1026 if (rval == 1)
1027 leave_it_hung = TRUE;
1028 if (rval >= 0)
1029 break;
1031 if (faulted(pri, dotrace) &&
1032 Mflag && !first && prismember(&flthang, what))
1033 leave_it_hung = TRUE;
1034 break;
1035 case PR_JOBCONTROL: /* can't happen except first time */
1036 req_flag = jobcontrol(pri, dotrace);
1037 break;
1038 case PR_SYSENTRY:
1039 /* protect ourself from operating system error */
1040 if (what <= 0 || what > PRMAXSYS)
1041 what = PRMAXSYS;
1042 pri->length = 0;
1044 * ow_in_effect checks to see whether or not we
1045 * are attempting to quantify the time spent in
1046 * a one way system call. This is necessary as
1047 * some system calls never return, yet it is desireable
1048 * to determine how much time the traced process
1049 * spends in these calls. To do this, a one way
1050 * flag is set on SYSENTRY when the call is recieved.
1051 * After this, the call mask for the SYSENTRY events
1052 * is filled so that the traced process will stop
1053 * on the entry to the very next system call.
1054 * This appears to the the best way to determine
1055 * system time elapsed between a one way system call.
1056 * Once the next call occurs, values that have been
1057 * stashed are used to record the correct syscall
1058 * and time, and the SYSENTRY event mask is restored
1059 * so that the traced process may continue.
1061 if (dotrace && ow_in_effect) {
1062 if (cflag) {
1063 (void) mutex_lock(&count_lock);
1064 scp = Cp->syscount[ow_syscall];
1065 if (ow_subcode != -1)
1066 scp += ow_subcode;
1067 scp->count++;
1068 accumulate(&scp->stime,
1069 &Lsp->pr_stime, &pri->syslast);
1070 accumulate(&Cp->usrtotal,
1071 &Lsp->pr_utime, &pri->usrlast);
1072 pri->syslast = Lsp->pr_stime;
1073 pri->usrlast = Lsp->pr_utime;
1074 (void) mutex_unlock(&count_lock);
1075 } else if (Eflag) {
1076 putpname(pri);
1077 timestamp(pri);
1078 (void) printf("%s\n", ow_string);
1079 free(ow_string);
1080 ow_string = NULL;
1081 pri->syslast = Lsp->pr_stime;
1083 ow_in_effect = 0;
1084 Psetsysentry(Proc, &running_set);
1088 * Special cases. Most syscalls are traced on exit.
1090 switch (what) {
1091 case SYS_exit: /* exit() */
1092 case SYS_lwp_exit: /* lwp_exit() */
1093 case SYS_context: /* [get|set]context() */
1094 if (dotrace && cflag &&
1095 prismember(&trace, what)) {
1096 ow_in_effect = 1;
1097 ow_syscall = what;
1098 ow_subcode = getsubcode(pri);
1099 pri->syslast = Lsp->pr_stime;
1100 running_set =
1101 (Pstatus(Proc))->pr_sysentry;
1102 Psetsysentry(Proc, &full_set);
1103 } else if (dotrace && Eflag &&
1104 prismember(&trace, what)) {
1105 (void) sysentry(pri, dotrace);
1106 ow_in_effect = 1;
1107 ow_string = my_malloc(
1108 strlen(pri->sys_string) + 1, NULL);
1109 (void) strcpy(ow_string,
1110 pri->sys_string);
1111 running_set =
1112 (Pstatus(Proc))->pr_sysentry;
1113 Psetsysentry(Proc, &full_set);
1114 pri->syslast = Lsp->pr_stime;
1115 } else if (dotrace &&
1116 prismember(&trace, what)) {
1117 (void) sysentry(pri, dotrace);
1118 putpname(pri);
1119 timestamp(pri);
1120 pri->length +=
1121 printf("%s\n", pri->sys_string);
1122 Flush();
1124 pri->sys_leng = 0;
1125 *pri->sys_string = '\0';
1127 if (what == SYS_exit)
1128 exit_called = TRUE;
1129 break;
1130 case SYS_execve:
1131 show_cred(pri, FALSE, TRUE);
1132 (void) sysentry(pri, dotrace);
1133 if (dotrace && !cflag &&
1134 prismember(&trace, what)) {
1135 pri->exec_string =
1136 my_realloc(pri->exec_string,
1137 strlen(pri->sys_string) + 1,
1138 NULL);
1139 (void) strcpy(pri->exec_pname,
1140 pri->pname);
1141 (void) strcpy(pri->exec_string,
1142 pri->sys_string);
1143 pri->length += strlen(pri->sys_string);
1144 pri->exec_lwpid = Lsp->pr_lwpid;
1146 pri->sys_leng = 0;
1147 *pri->sys_string = '\0';
1148 break;
1149 default:
1150 if (dotrace && (cflag || Eflag) &&
1151 prismember(&trace, what)) {
1152 pri->syslast = Lsp->pr_stime;
1154 break;
1156 if (dotrace && Tflag && !first &&
1157 (prismember(&syshang, what) ||
1158 (exit_called && prismember(&syshang, SYS_exit))))
1159 leave_it_hung = TRUE;
1160 break;
1161 case PR_SYSEXIT:
1162 /* check for write open of a /proc file */
1163 if (what == SYS_openat || what == SYS_openat64 ||
1164 what == SYS_open || what == SYS_open64) {
1165 int readonly;
1167 (void) sysentry(pri, dotrace);
1168 pri->Errno = Lsp->pr_errno;
1169 pri->ErrPriv = Lsp->pr_errpriv;
1170 readonly =
1171 ((what == SYS_openat ||
1172 what == SYS_openat64) &&
1173 pri->sys_nargs > 2 &&
1174 (pri->sys_args[2]&0x3) == O_RDONLY) ||
1175 ((what == SYS_open ||
1176 what == SYS_open64) &&
1177 pri->sys_nargs > 1 &&
1178 (pri->sys_args[1]&0x3) == O_RDONLY);
1179 if ((pri->Errno == 0 || pri->Errno == EBUSY) &&
1180 pri->sys_valid && !readonly) {
1181 int rv = checkproc(pri);
1182 if (rv == 1 && Fflag != PGRAB_FORCE) {
1184 * The process opened itself
1185 * and no -F flag was specified.
1186 * Just print the open() call
1187 * and let go of the process.
1189 if (dotrace && !cflag &&
1190 prismember(&trace, what)) {
1191 putpname(pri);
1192 timestamp(pri);
1193 (void) printf("%s\n",
1194 pri->sys_string);
1195 Flush();
1197 sigusr1 = TRUE;
1198 (void) mutex_unlock(
1199 &truss_lock);
1200 goto out;
1202 if (rv == 2) {
1204 * Process opened someone else.
1205 * The open is being reissued.
1206 * Don't report this one.
1208 pri->sys_leng = 0;
1209 *pri->sys_string = '\0';
1210 pri->sys_nargs = 0;
1211 break;
1215 if (what == SYS_execve && pri->Errno == 0) {
1217 * Refresh the data model on exec() in case it
1218 * is different from the parent. Lwait()
1219 * doesn't update process-wide status, so we
1220 * have to explicitly call Pstopstatus() to get
1221 * the new state.
1223 (void) Pstopstatus(Proc, PCNULL, 0);
1224 data_model = Psp->pr_dmodel;
1226 if (sysexit(pri, dotrace))
1227 Flush();
1228 if (what == SYS_lwp_create && pri->Rval1 != 0) {
1229 struct ps_lwphandle *new_Lwp;
1230 lwpid_t lwpid;
1232 if ((new_Lwp = grab_lwp(pri->Rval1)) != NULL) {
1233 (void) thr_sigsetmask(SIG_SETMASK,
1234 &fillset, NULL);
1235 if (thr_create(NULL, 0, worker_thread,
1236 new_Lwp, THR_BOUND | THR_SUSPENDED,
1237 &lwpid) != 0)
1238 abend("cannot create lwp ",
1239 "to follow child lwp");
1240 insert_lwpid(lwpid);
1241 (void) thr_continue(lwpid);
1242 (void) thr_sigsetmask(SIG_SETMASK,
1243 &emptyset, NULL);
1246 pri->sys_nargs = 0;
1247 if (dotrace && Tflag && !first &&
1248 prismember(&syshang, what))
1249 leave_it_hung = TRUE;
1250 if (what == SYS_execve && pri->Errno == 0) {
1251 is_vfork_child = FALSE;
1252 reset_breakpoints();
1254 * exec() resets the calling LWP's lwpid to 1.
1255 * If the LWP has changed its lwpid, then
1256 * we have to free and re-grab the LWP
1257 * in order to keep libproc consistent.
1258 * This "cannot fail".
1260 if (who != Lsp->pr_lwpid) {
1262 * We must wait for all of our
1263 * siblings to terminate.
1265 while (truss_nlwp > 1)
1266 (void) cond_wait(&truss_cv,
1267 &truss_lock);
1268 who = Lsp->pr_lwpid;
1269 Lfree(Lwp);
1270 pri->Lwp = Lwp =
1271 Lgrab(Proc, who, &gcode);
1272 if (Lwp == NULL)
1273 abend("Lgrab error: ",
1274 Lgrab_error(gcode));
1275 pri->lwpstat = Lsp = Lstatus(Lwp);
1278 break;
1279 default:
1280 req_flag = 0;
1281 (void) fprintf(stderr,
1282 "unknown reason for stopping: %d/%d\n",
1283 Lsp->pr_why, what);
1284 abend(NULL, NULL);
1287 if (pri->child) { /* controlled process fork()ed */
1288 if (fflag || Dynpat != NULL) {
1289 if (Lsp->pr_why == PR_SYSEXIT &&
1290 (Lsp->pr_what == SYS_vfork ||
1291 (Lsp->pr_what == SYS_forksys &&
1292 Lsp->pr_sysarg[0] == 2))) {
1293 is_vfork_child = TRUE;
1294 (void) Pstop(Proc, 0);
1296 if (control(pri, pri->child)) {
1297 (void) mutex_unlock(&truss_lock);
1298 pri->child = 0;
1299 if (!fflag) {
1301 * If this is vfork(), then
1302 * this clears the breakpoints
1303 * in the parent's address space
1304 * as well as in the child's.
1306 clear_breakpoints();
1307 Prelease(Proc, PRELEASE_CLEAR);
1308 _exit(0);
1310 main_thread(FALSE);
1311 /* NOTREACHED */
1315 * Here, we are still the parent truss.
1316 * If the child messes with the breakpoints and
1317 * this is vfork(), we have to set them again.
1319 if (Dynpat != NULL && is_vfork_child && !fflag)
1320 reset_traps = TRUE;
1321 is_vfork_child = FALSE;
1323 pri->child = 0;
1326 if (leave_it_hung) {
1327 (void) mutex_unlock(&truss_lock);
1328 break;
1331 if (reset_traps) {
1333 * To recover from vfork, we must catch the lwp
1334 * that issued the vfork() when it returns to user
1335 * level, with all other lwps remaining stopped.
1336 * For this purpose, we have directed all lwps to
1337 * stop and we now set the vfork()ing lwp running
1338 * with the PRSTEP flag. We expect to capture it
1339 * when it stops again showing PR_FAULTED/FLTTRACE.
1340 * We are holding truss_lock, so no other threads
1341 * in truss will set any other lwps in the victim
1342 * process running.
1344 reset_traps = FALSE;
1345 (void) Lsetrun(Lwp, 0, PRSTEP);
1346 do {
1347 (void) Lwait(Lwp, 0);
1348 } while (Lstate(Lwp) == PS_RUN);
1349 if (Lstate(Lwp) == PS_STOP &&
1350 Lsp->pr_why == PR_FAULTED &&
1351 Lsp->pr_what == FLTTRACE) {
1352 reestablish_traps();
1353 (void) Lsetrun(Lwp, 0, PRCFAULT|PRSTOP);
1354 } else {
1355 (void) printf("%s\t*** Expected PR_FAULTED/"
1356 "FLTTRACE stop following vfork()\n",
1357 pri->pname);
1361 if (Lstate(Lwp) == PS_STOP) {
1362 int flags = 0;
1364 if (interrupt | sigusr1) {
1365 (void) mutex_unlock(&truss_lock);
1366 break;
1369 * If we must leave this lwp hung is sympathy with
1370 * another lwp that is being left hung on purpose,
1371 * then push the state onward toward PR_REQUESTED.
1373 if (leave_hung) {
1374 if (Lsp->pr_why == PR_REQUESTED) {
1375 (void) mutex_unlock(&truss_lock);
1376 break;
1378 flags |= PRSTOP;
1380 if (Lsetrun(Lwp, 0, flags) != 0 &&
1381 Lstate(Lwp) != PS_LOST &&
1382 Lstate(Lwp) != PS_UNDEAD) {
1383 (void) mutex_unlock(&truss_lock);
1384 perror("Lsetrun");
1385 abend("cannot start subject lwp", NULL);
1386 /* NOTREACHED */
1389 first = FALSE;
1391 (void) mutex_unlock(&truss_lock);
1394 out:
1395 /* block all signals in preparation for exiting */
1396 (void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL);
1398 if (Lstate(Lwp) == PS_UNDEAD || Lstate(Lwp) == PS_LOST)
1399 (void) mutex_lock(&truss_lock);
1400 else {
1401 (void) Lstop(Lwp, MILLISEC);
1402 (void) mutex_lock(&truss_lock);
1403 if (Lstate(Lwp) == PS_STOP &&
1404 Lsp->pr_why == PR_FAULTED &&
1405 Lsp->pr_what == FLTBPT)
1406 (void) function_trace(pri, 0, 1, dotrace);
1409 if (dotrace && ow_in_effect) {
1410 if (cflag) {
1411 (void) mutex_lock(&count_lock);
1412 scp = Cp->syscount[ow_syscall];
1413 if (ow_subcode != -1)
1414 scp += ow_subcode;
1415 scp->count++;
1416 accumulate(&scp->stime,
1417 &Lsp->pr_stime, &pri->syslast);
1418 accumulate(&Cp->usrtotal,
1419 &Lsp->pr_utime, &pri->usrlast);
1420 pri->syslast = Lsp->pr_stime;
1421 pri->usrlast = Lsp->pr_utime;
1422 (void) mutex_unlock(&count_lock);
1423 } else if (Eflag) {
1424 putpname(pri);
1425 timestamp(pri);
1426 (void) printf("%s\n", ow_string);
1427 free(ow_string);
1428 ow_string = NULL;
1429 pri->syslast = Lsp->pr_stime;
1431 ow_in_effect = 0;
1432 Psetsysentry(Proc, &running_set);
1435 if (Lstate(Lwp) == PS_UNDEAD || Lstate(Lwp) == PS_LOST) {
1437 * The victim thread has exited or we lost control of
1438 * the process. Remove ourself from the list of all
1439 * truss threads and notify everyone waiting for this.
1441 lwpid_t my_id = thr_self();
1442 int i;
1444 for (i = 0; i < truss_maxlwp; i++) {
1445 if (truss_lwpid[i] == my_id) {
1446 truss_lwpid[i] = 0;
1447 break;
1450 if (--truss_nlwp != 0) {
1451 (void) cond_broadcast(&truss_cv);
1452 } else {
1454 * The last truss worker thread is terminating.
1455 * The address space is gone (UNDEAD) or is
1456 * inaccessible (LOST) so we cannot clear the
1457 * breakpoints. Just report the htable stats.
1459 report_htable_stats();
1461 } else {
1463 * The victim thread is not a zombie thread, and we have not
1464 * lost control of the process. We must have gotten here due
1465 * to (leave_hung || leave_it_hung || interrupt || sigusr1).
1466 * In these cases, we must carefully uninstrument the process
1467 * and either set it running or leave it stopped and abandoned.
1469 static int nstopped = 0;
1470 static int cleared = 0;
1472 if (leave_it_hung)
1473 leave_hung = TRUE;
1474 if ((leave_hung | interrupt | sigusr1) == 0)
1475 abend("(leave_hung | interrupt | sigusr1) == 0", NULL);
1478 * The first truss thread through here needs to instruct all
1479 * application threads to stop -- they're not necessarily
1480 * going to stop on their own.
1482 if (nstopped++ == 0)
1483 (void) Pdstop(Proc);
1486 * Notify all other worker threads about the reason
1487 * for being here (leave_hung || interrupt || sigusr1).
1489 broadcast_signals();
1492 * Once the last thread has reached this point, then and
1493 * only then is it safe to remove breakpoints and other
1494 * instrumentation. Since breakpoints are executed without
1495 * truss_lock held, a monitor thread can't exit until all
1496 * breakpoints have been removed, and we can't be sure the
1497 * procedure to execute a breakpoint won't temporarily
1498 * reinstall a breakpont. Accordingly, we need to wait
1499 * until all threads are in a known state.
1501 while (nstopped != truss_nlwp)
1502 (void) cond_wait(&truss_cv, &truss_lock);
1505 * All truss threads have reached this point.
1506 * One of them clears the breakpoints and
1507 * wakes up everybody else to finish up.
1509 if (cleared++ == 0) {
1511 * All threads should already be stopped,
1512 * but just to be safe...
1514 (void) Pstop(Proc, MILLISEC);
1515 clear_breakpoints();
1516 (void) Psysexit(Proc, SYS_vfork, FALSE);
1517 (void) Psysexit(Proc, SYS_forksys, FALSE);
1518 (void) Punsetflags(Proc, PR_FORK);
1519 Psync(Proc);
1520 fflag = 0;
1521 (void) cond_broadcast(&truss_cv);
1524 if (!leave_hung && Lstate(Lwp) == PS_STOP)
1525 (void) Lsetrun(Lwp, 0, 0);
1528 (void) Lfree(Lwp);
1529 (void) mutex_unlock(&truss_lock);
1530 return (NULL);
1534 * Give a base date for time stamps, adjusted to the
1535 * stop time of the selected (first or created) process.
1537 void
1538 setup_basetime(hrtime_t basehrtime, struct timeval *basedate)
1540 const pstatus_t *Psp = Pstatus(Proc);
1541 (void) mutex_lock(&count_lock);
1542 Cp->basetime = Psp->pr_lwp.pr_tstamp;
1543 (void) mutex_unlock(&count_lock);
1545 if ((dflag|Dflag) && !cflag) {
1546 const struct tm *ptm;
1547 const char *ptime;
1548 const char *pdst;
1549 hrtime_t delta = basehrtime -
1550 ((hrtime_t)Cp->basetime.tv_sec * NANOSEC +
1551 Cp->basetime.tv_nsec);
1553 if (delta > 0) {
1554 basedate->tv_sec -= (time_t)(delta / NANOSEC);
1555 basedate->tv_usec -= (delta % NANOSEC) / 1000;
1556 if (basedate->tv_usec < 0) {
1557 basedate->tv_sec--;
1558 basedate->tv_usec += MICROSEC;
1561 ptm = localtime(&basedate->tv_sec);
1562 ptime = asctime(ptm);
1563 if ((pdst = tzname[ptm->tm_isdst ? 1 : 0]) == NULL)
1564 pdst = "???";
1565 if (dflag) {
1566 (void) printf(
1567 "Base time stamp: %ld.%4.4ld [ %.20s%s %.4s ]\n",
1568 basedate->tv_sec, basedate->tv_usec / 100,
1569 ptime, pdst, ptime + 20);
1570 Flush();
1576 * Performs per-process initializations. If truss is following a victim
1577 * process it will fork additional truss processes to follow new processes
1578 * created. Here is where each new truss process gets its per-process data
1579 * initialized.
1582 void
1583 per_proc_init()
1585 void *pmem;
1586 struct timeval basedate;
1587 hrtime_t basehrtime;
1588 struct syscount *scp;
1589 int i;
1590 timestruc_t c_basetime;
1592 /* Make sure we only configure the basetime for the first truss proc */
1594 if (Cp == NULL) {
1595 pmem = my_malloc(sizeof (struct counts) + maxsyscalls() *
1596 sizeof (struct syscount), NULL);
1597 Cp = (struct counts *)pmem;
1598 basehrtime = gethrtime();
1599 (void) gettimeofday(&basedate, NULL);
1600 setup_basetime(basehrtime, &basedate);
1603 c_basetime = Cp->basetime;
1605 (void) memset(Cp, 0, sizeof (struct counts) + maxsyscalls() *
1606 sizeof (struct syscount));
1608 Cp->basetime = c_basetime;
1610 if (fcall_tbl != NULL)
1611 destroy_hash(fcall_tbl);
1612 fcall_tbl = init_hash(4096);
1614 (void) mutex_lock(&count_lock);
1615 scp = (struct syscount *)(Cp + 1);
1616 for (i = 0; i <= PRMAXSYS; i++) {
1617 Cp->syscount[i] = scp;
1618 scp += nsubcodes(i);
1620 (void) mutex_unlock(&count_lock);
1625 * Writes child state to a tempfile where it can be read and
1626 * accumulated by the parent process. The file descriptor is shared
1627 * among the processes. Ordering of writes does not matter, it is, however,
1628 * necessary to ensure that all writes are atomic.
1631 void
1632 child_to_file()
1634 hiter_t *itr;
1635 hentry_t *ntry;
1636 hdntry_t fentry;
1637 char *s = NULL;
1638 char *t = NULL;
1639 unsigned char *buf = NULL;
1640 size_t bufsz = 0;
1641 size_t i = 0;
1642 size_t j = 0;
1644 /* ensure that we are in fact a child process */
1645 if (!descendent)
1646 return;
1648 /* enumerate fcall_tbl (tbl locked until freed) */
1649 if (Dynpat != NULL) {
1650 itr = iterate_hash(fcall_tbl);
1652 ntry = iter_next(itr);
1653 while (ntry != NULL) {
1654 fentry.type = HD_hashntry;
1655 fentry.count = ntry->count;
1656 s = ntry->key;
1657 t = ntry->lib;
1658 i = strlen(s) + 1;
1659 j = strlen(t) + 1;
1660 fentry.sz_key = i;
1661 fentry.sz_lib = j;
1662 if (i + sizeof (fentry) > bufsz) {
1663 buf = my_realloc(buf, i + j + sizeof (fentry),
1664 NULL);
1665 bufsz = i + j + sizeof (fentry);
1667 (void) memcpy(buf, &fentry, sizeof (fentry));
1668 (void) strlcpy((char *)(buf + sizeof (fentry)), t, j);
1669 (void) strlcpy((char *)(buf + sizeof (fentry) + j),
1670 s, i);
1671 if (write(sfd, buf, sizeof (fentry) + i + j) == -1)
1672 abend("Error writing to tmp file", NULL);
1673 ntry = iter_next(itr);
1675 iter_free(itr);
1678 /* Now write the count/syscount structs down */
1679 bufsz = sizeof (fentry) + (sizeof (struct counts) + maxsyscalls() *
1680 sizeof (struct syscount));
1681 buf = my_realloc(buf, bufsz, NULL);
1682 fentry.type = HD_cts_syscts;
1683 fentry.count = 0; /* undefined, really */
1684 fentry.sz_key = bufsz - sizeof (fentry);
1685 fentry.sz_lib = 0; /* also undefined */
1686 (void) memcpy(buf, &fentry, sizeof (fentry));
1687 (void) memcpy((char *)(buf + sizeof (fentry)), Cp,
1688 bufsz - sizeof (fentry));
1689 if (write(sfd, buf, bufsz) == -1)
1690 abend("Error writing cts/syscts to tmpfile", NULL);
1692 free(buf);
1696 * The following reads entries from the tempfile back to the parent
1697 * so that information can be collected and summed for overall statistics.
1698 * This reads records out of the tempfile. If they are hash table entries,
1699 * the record is merged with the hash table kept by the parent process.
1700 * If the information is a struct count/struct syscount pair, they are
1701 * copied and added into the count/syscount array kept by the parent.
1704 void
1705 file_to_parent()
1707 hdntry_t ntry;
1708 char *s = NULL;
1709 char *t = NULL;
1710 size_t c_offset = 0;
1711 size_t filesz;
1712 size_t t_strsz = 0;
1713 size_t s_strsz = 0;
1714 struct stat fsi;
1716 if (descendent)
1717 return;
1719 if (fstat(sfd, &fsi) == -1)
1720 abend("Error stat-ing tempfile", NULL);
1721 filesz = fsi.st_size;
1723 while (c_offset < filesz) {
1724 /* first get hdntry */
1725 if (pread(sfd, &ntry, sizeof (hdntry_t), c_offset) !=
1726 sizeof (hdntry_t))
1727 abend("Unable to perform full read of hdntry", NULL);
1728 c_offset += sizeof (hdntry_t);
1730 switch (ntry.type) {
1731 case HD_hashntry:
1733 /* first get lib string */
1734 if (ntry.sz_lib > t_strsz) {
1735 t = my_realloc(t, ntry.sz_lib, NULL);
1736 t_strsz = ntry.sz_lib;
1739 (void) memset(t, 0, t_strsz);
1741 /* now actually get the string */
1742 if (pread(sfd, t, ntry.sz_lib, c_offset) != ntry.sz_lib)
1743 abend("Unable to perform full read of lib str",
1744 NULL);
1745 c_offset += ntry.sz_lib;
1747 /* now get key string */
1749 if (ntry.sz_key > s_strsz) {
1750 s = my_realloc(s, ntry.sz_key, NULL);
1751 s_strsz = ntry.sz_key;
1753 (void) memset(s, 0, s_strsz);
1754 if (pread(sfd, s, ntry.sz_key, c_offset) != ntry.sz_key)
1755 abend("Unable to perform full read of key str",
1756 NULL);
1757 c_offset += ntry.sz_key;
1759 add_fcall(fcall_tbl, t, s, ntry.count);
1760 break;
1762 case HD_cts_syscts:
1764 struct counts *ncp;
1765 size_t bfsz = sizeof (struct counts) + maxsyscalls()
1766 * sizeof (struct syscount);
1767 int i;
1768 struct syscount *sscp;
1770 if (ntry.sz_key != bfsz)
1771 abend("cts/syscts size does not sanity check",
1772 NULL);
1773 ncp = my_malloc(ntry.sz_key, NULL);
1775 if (pread(sfd, ncp, ntry.sz_key, c_offset) !=
1776 ntry.sz_key)
1777 abend("Unable to perform full read of cts",
1778 NULL);
1779 c_offset += ntry.sz_key;
1781 sscp = (struct syscount *)(ncp + 1);
1783 (void) mutex_lock(&count_lock);
1785 Cp->usrtotal.tv_sec += ncp->usrtotal.tv_sec;
1786 Cp->usrtotal.tv_nsec += ncp->usrtotal.tv_nsec;
1787 if (Cp->usrtotal.tv_nsec >= NANOSEC) {
1788 Cp->usrtotal.tv_nsec -= NANOSEC;
1789 Cp->usrtotal.tv_sec++;
1791 for (i = 0; i <= PRMAXSYS; i++) {
1792 ncp->syscount[i] = sscp;
1793 sscp += nsubcodes(i);
1796 for (i = 0; i <= PRMAXFAULT; i++) {
1797 Cp->fltcount[i] += ncp->fltcount[i];
1800 for (i = 0; i <= PRMAXSIG; i++) {
1801 Cp->sigcount[i] += ncp->sigcount[i];
1804 for (i = 0; i <= PRMAXSYS; i++) {
1805 struct syscount *scp = Cp->syscount[i];
1806 struct syscount *nscp = ncp->syscount[i];
1807 int n = nsubcodes(i);
1808 int subcode;
1810 for (subcode = 0; subcode < n; subcode++,
1811 scp++, nscp++) {
1812 scp->count += nscp->count;
1813 scp->error += nscp->error;
1814 scp->stime.tv_sec += nscp->stime.tv_sec;
1815 scp->stime.tv_nsec +=
1816 nscp->stime.tv_nsec;
1817 if (scp->stime.tv_nsec >= NANOSEC) {
1818 scp->stime.tv_nsec -= NANOSEC;
1819 scp->stime.tv_sec++;
1823 (void) mutex_unlock(&count_lock);
1824 free(ncp);
1825 break;
1827 default:
1829 abend("Unknown file entry type encountered", NULL);
1830 break;
1834 if (fstat(sfd, &fsi) == -1)
1835 abend("Error stat-ing tempfile", NULL);
1836 filesz = fsi.st_size;
1838 if (s != NULL)
1839 free(s);
1840 if (t != NULL)
1841 free(t);
1844 void
1845 make_pname(private_t *pri, id_t tid)
1847 if (!cflag) {
1848 int ff = (fflag || ngrab > 1);
1849 int lf = (lflag | tid | (Thr_agent != NULL) | (truss_nlwp > 1));
1850 pid_t pid = Pstatus(Proc)->pr_pid;
1851 id_t lwpid = pri->lwpstat->pr_lwpid;
1853 if (ff != pri->pparam.ff ||
1854 lf != pri->pparam.lf ||
1855 pid != pri->pparam.pid ||
1856 lwpid != pri->pparam.lwpid ||
1857 tid != pri->pparam.tid) {
1858 char *s = pri->pname;
1860 if (ff)
1861 s += sprintf(s, "%d", (int)pid);
1862 if (lf)
1863 s += sprintf(s, "/%d", (int)lwpid);
1864 if (tid)
1865 s += sprintf(s, "@%d", (int)tid);
1866 if (ff || lf)
1867 *s++ = ':', *s++ = '\t';
1868 if (ff && lf && s < pri->pname + 9)
1869 *s++ = '\t';
1870 *s = '\0';
1871 pri->pparam.ff = ff;
1872 pri->pparam.lf = lf;
1873 pri->pparam.pid = pid;
1874 pri->pparam.lwpid = lwpid;
1875 pri->pparam.tid = tid;
1881 * Print the pri->pname[] string, if any.
1883 void
1884 putpname(private_t *pri)
1886 if (pri->pname[0])
1887 (void) fputs(pri->pname, stdout);
1891 * Print the timestamp, if requested (-d, -D, or -E).
1893 void
1894 timestamp(private_t *pri)
1896 const lwpstatus_t *Lsp = pri->lwpstat;
1897 int seconds;
1898 int fraction;
1900 if (!(dflag|Dflag|Eflag) || !(Lsp->pr_flags & PR_STOPPED))
1901 return;
1903 seconds = Lsp->pr_tstamp.tv_sec - Cp->basetime.tv_sec;
1904 fraction = Lsp->pr_tstamp.tv_nsec - Cp->basetime.tv_nsec;
1905 if (fraction < 0) {
1906 seconds--;
1907 fraction += NANOSEC;
1909 /* fraction in 1/10 milliseconds, rounded up */
1910 fraction = (fraction + 50000) / 100000;
1911 if (fraction >= (MILLISEC * 10)) {
1912 seconds++;
1913 fraction -= (MILLISEC * 10);
1916 if (dflag) /* time stamp */
1917 (void) printf("%2d.%4.4d\t", seconds, fraction);
1919 if (Dflag) { /* time delta */
1920 int oseconds = pri->seconds;
1921 int ofraction = pri->fraction;
1923 pri->seconds = seconds;
1924 pri->fraction = fraction;
1925 seconds -= oseconds;
1926 fraction -= ofraction;
1927 if (fraction < 0) {
1928 seconds--;
1929 fraction += (MILLISEC * 10);
1931 (void) printf("%2d.%4.4d\t", seconds, fraction);
1934 if (Eflag) {
1935 seconds = Lsp->pr_stime.tv_sec - pri->syslast.tv_sec;
1936 fraction = Lsp->pr_stime.tv_nsec - pri->syslast.tv_nsec;
1938 if (fraction < 0) {
1939 seconds--;
1940 fraction += NANOSEC;
1942 /* fraction in 1/10 milliseconds, rounded up */
1943 fraction = (fraction + 50000) / 100000;
1944 if (fraction >= (MILLISEC * 10)) {
1945 seconds++;
1946 fraction -= (MILLISEC * 10);
1948 (void) printf("%2d.%4.4d\t", seconds, fraction);
1953 * Create output file, being careful about
1954 * suid/sgid and file descriptor 0, 1, 2 issues.
1957 xcreat(char *path)
1959 int fd;
1960 int mode = 0666;
1962 if (Euid == Ruid && Egid == Rgid) /* not set-id */
1963 fd = creat(path, mode);
1964 else if (access(path, F_OK) != 0) { /* file doesn't exist */
1965 /* if directory permissions OK, create file & set ownership */
1967 char *dir;
1968 char *p;
1969 char dot[4];
1971 /* generate path for directory containing file */
1972 if ((p = strrchr(path, '/')) == NULL) { /* no '/' */
1973 p = dir = dot;
1974 *p++ = '.'; /* current directory */
1975 *p = '\0';
1976 } else if (p == path) { /* leading '/' */
1977 p = dir = dot;
1978 *p++ = '/'; /* root directory */
1979 *p = '\0';
1980 } else { /* embedded '/' */
1981 dir = path; /* directory path */
1982 *p = '\0';
1985 if (access(dir, W_OK|X_OK) != 0) {
1986 /* not writeable/searchable */
1987 *p = '/';
1988 fd = -1;
1989 } else { /* create file and set ownership correctly */
1990 *p = '/';
1991 if ((fd = creat(path, mode)) >= 0)
1992 (void) chown(path, (int)Ruid, (int)Rgid);
1994 } else if (access(path, W_OK) != 0) /* file not writeable */
1995 fd = -1;
1996 else
1997 fd = creat(path, mode);
2000 * Make sure it's not one of 0, 1, or 2.
2001 * This allows truss to work when spawned by init(1m).
2003 if (0 <= fd && fd <= 2) {
2004 int dfd = fcntl(fd, F_DUPFD, 3);
2005 (void) close(fd);
2006 fd = dfd;
2010 * Mark it close-on-exec so created processes don't inherit it.
2012 if (fd >= 0)
2013 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
2015 return (fd);
2018 void
2019 setoutput(int ofd)
2021 if (ofd < 0) {
2022 (void) close(1);
2023 (void) fcntl(2, F_DUPFD, 1);
2024 } else if (ofd != 1) {
2025 (void) close(1);
2026 (void) fcntl(ofd, F_DUPFD, 1);
2027 (void) close(ofd);
2028 /* if no stderr, make it the same file */
2029 if ((ofd = dup(2)) < 0)
2030 (void) fcntl(1, F_DUPFD, 2);
2031 else
2032 (void) close(ofd);
2037 * Accumulate time differencies: a += e - s;
2039 void
2040 accumulate(timestruc_t *ap, const timestruc_t *ep, const timestruc_t *sp)
2042 ap->tv_sec += ep->tv_sec - sp->tv_sec;
2043 ap->tv_nsec += ep->tv_nsec - sp->tv_nsec;
2044 if (ap->tv_nsec >= NANOSEC) {
2045 ap->tv_nsec -= NANOSEC;
2046 ap->tv_sec++;
2047 } else if (ap->tv_nsec < 0) {
2048 ap->tv_nsec += NANOSEC;
2049 ap->tv_sec--;
2054 lib_sort(const void *p1, const void *p2)
2056 int cmpr = 0;
2057 long i;
2058 long j;
2060 hentry_t *t1 = (hentry_t *)p1;
2061 hentry_t *t2 = (hentry_t *)p2;
2063 char *p = t1->lib;
2064 char *q = t2->lib;
2066 if ((cmpr = strcmp(p, q)) == 0) {
2067 i = t1->count;
2068 j = t2->count;
2069 if (i > j)
2070 return (-1);
2071 else if (i < j)
2072 return (1);
2073 else {
2074 p = t1->key;
2075 q = t2->key;
2076 return (strcmp(p, q));
2078 } else
2079 return (cmpr);
2082 void
2083 report(private_t *pri, time_t lapse) /* elapsed time, clock ticks */
2085 int i;
2086 long count;
2087 const char *name;
2088 long error;
2089 long total;
2090 long errtot;
2091 timestruc_t tickzero;
2092 timestruc_t ticks;
2093 timestruc_t ticktot;
2095 if (descendent)
2096 return;
2098 for (i = 0, total = 0; i <= PRMAXFAULT && !interrupt; i++) {
2099 if ((count = Cp->fltcount[i]) != 0) {
2100 if (total == 0) /* produce header */
2101 (void) printf("faults -------------\n");
2103 name = proc_fltname(i, pri->flt_name,
2104 sizeof (pri->flt_name));
2106 (void) printf("%s%s\t%4ld\n", name,
2107 (((int)strlen(name) < 8)?
2108 (const char *)"\t" : (const char *)""),
2109 count);
2110 total += count;
2113 if (total && !interrupt)
2114 (void) printf("total:\t\t%4ld\n\n", total);
2116 for (i = 0, total = 0; i <= PRMAXSIG && !interrupt; i++) {
2117 if ((count = Cp->sigcount[i]) != 0) {
2118 if (total == 0) /* produce header */
2119 (void) printf("signals ------------\n");
2120 name = signame(pri, i);
2121 (void) printf("%s%s\t%4ld\n", name,
2122 (((int)strlen(name) < 8)?
2123 (const char *)"\t" : (const char *)""),
2124 count);
2125 total += count;
2128 if (total && !interrupt)
2129 (void) printf("total:\t\t%4ld\n\n", total);
2131 if ((Dynpat != NULL) && !interrupt) {
2132 size_t elem = elements_in_table(fcall_tbl);
2133 hiter_t *itr = iterate_hash(fcall_tbl);
2134 hentry_t *tmp = iter_next(itr);
2135 hentry_t *stbl = my_malloc(elem * sizeof (hentry_t), NULL);
2136 i = 0;
2137 while ((tmp != NULL) && (i < elem)) {
2138 stbl[i].prev = tmp->prev;
2139 stbl[i].next = tmp->next;
2140 stbl[i].lib = tmp->lib;
2141 stbl[i].key = tmp->key;
2142 stbl[i].count = tmp->count;
2143 tmp = iter_next(itr);
2144 i++;
2146 qsort((void *)stbl, elem, sizeof (hentry_t),
2147 lib_sort);
2148 (void) printf(
2149 "\n%-20s %-40s %s\n", "Library:", "Function", "calls");
2150 for (i = 0; i < elem; i++) {
2151 (void) printf("%-20s %-40s %ld\n", stbl[i].lib,
2152 stbl[i].key, stbl[i].count);
2154 iter_free(itr);
2155 free(stbl);
2156 itr = NULL;
2159 if (!interrupt)
2160 (void) printf(
2161 "\nsyscall seconds calls errors\n");
2163 total = errtot = 0;
2164 tickzero.tv_sec = ticks.tv_sec = ticktot.tv_sec = 0;
2165 tickzero.tv_nsec = ticks.tv_nsec = ticktot.tv_nsec = 0;
2166 for (i = 0; i <= PRMAXSYS && !interrupt; i++) {
2167 struct syscount *scp = Cp->syscount[i];
2168 int n = nsubcodes(i);
2169 int subcode;
2171 for (subcode = 0; subcode < n; subcode++, scp++) {
2172 if ((count = scp->count) != 0 || scp->error) {
2173 (void) printf("%-19.19s ",
2174 sysname(pri, i, subcode));
2176 ticks = scp->stime;
2177 accumulate(&ticktot, &ticks, &tickzero);
2178 prtim(&ticks);
2180 (void) printf(" %7ld", count);
2181 if ((error = scp->error) != 0)
2182 (void) printf(" %7ld", error);
2183 (void) fputc('\n', stdout);
2184 total += count;
2185 errtot += error;
2190 if (!interrupt) {
2191 (void) printf(
2192 " -------- ------ ----\n");
2193 (void) printf("sys totals: ");
2194 prtim(&ticktot);
2195 (void) printf(" %7ld %6ld\n", total, errtot);
2198 if (!interrupt) {
2199 (void) printf("usr time: ");
2200 prtim(&Cp->usrtotal);
2201 (void) fputc('\n', stdout);
2204 if (!interrupt) {
2205 int hz = (int)sysconf(_SC_CLK_TCK);
2207 ticks.tv_sec = lapse / hz;
2208 ticks.tv_nsec = (lapse % hz) * (1000000000 / hz);
2209 (void) printf("elapsed: ");
2210 prtim(&ticks);
2211 (void) fputc('\n', stdout);
2215 void
2216 prtim(timestruc_t *tp)
2218 time_t sec;
2220 if ((sec = tp->tv_sec) != 0) /* whole seconds */
2221 (void) printf("%5lu", sec);
2222 else
2223 (void) printf(" ");
2225 (void) printf(".%3.3ld", tp->tv_nsec/1000000); /* fraction */
2229 * Gather process id's.
2230 * Return 0 on success, != 0 on failure.
2232 void
2233 pids(char *arg, proc_set_t *grab)
2235 pid_t pid = -1;
2236 int i;
2237 const char *lwps = NULL;
2239 if ((pid = proc_arg_xpsinfo(arg, PR_ARG_PIDS, NULL, &i, &lwps)) < 0) {
2240 (void) fprintf(stderr, "%s: cannot trace '%s': %s\n",
2241 command, arg, Pgrab_error(i));
2242 return;
2245 for (i = 0; i < ngrab; i++)
2246 if (grab[i].pid == pid) /* duplicate */
2247 break;
2249 if (i == ngrab) {
2250 grab[ngrab].pid = pid;
2251 grab[ngrab].lwps = lwps;
2252 ngrab++;
2253 } else {
2254 (void) fprintf(stderr, "%s: duplicate process-id ignored: %d\n",
2255 command, (int)pid);
2260 * Report psargs string.
2262 void
2263 psargs(private_t *pri)
2265 pid_t pid = Pstatus(Proc)->pr_pid;
2266 psinfo_t psinfo;
2268 if (proc_get_psinfo(pid, &psinfo) == 0)
2269 (void) printf("%spsargs: %.64s\n",
2270 pri->pname, psinfo.pr_psargs);
2271 else {
2272 perror("psargs()");
2273 (void) printf("%s\t*** Cannot read psinfo file for pid %d\n",
2274 pri->pname, (int)pid);
2278 char *
2279 fetchstring(private_t *pri, long addr, int maxleng)
2281 int nbyte;
2282 int leng = 0;
2283 char string[41];
2285 string[40] = '\0';
2286 if (pri->str_bsize == 0) /* initial allocation of string buffer */
2287 pri->str_buffer =
2288 my_malloc(pri->str_bsize = 16, "string buffer");
2289 *pri->str_buffer = '\0';
2291 for (nbyte = 40; nbyte == 40 && leng < maxleng; addr += 40) {
2292 if ((nbyte = Pread(Proc, string, 40, addr)) <= 0)
2293 return (leng? pri->str_buffer : NULL);
2294 if (nbyte > 0 &&
2295 (nbyte = strlen(string)) > 0) {
2296 while (leng + nbyte >= pri->str_bsize)
2297 pri->str_buffer =
2298 my_realloc(pri->str_buffer,
2299 pri->str_bsize *= 2, "string buffer");
2300 (void) strcpy(pri->str_buffer+leng, string);
2301 leng += nbyte;
2305 if (leng > maxleng)
2306 leng = maxleng;
2307 pri->str_buffer[leng] = '\0';
2309 return (pri->str_buffer);
2312 static priv_set_t *
2313 getset(prpriv_t *p, priv_ptype_t set)
2315 return ((priv_set_t *)
2316 &p->pr_sets[priv_getsetbyname(set) * p->pr_setsize]);
2319 void
2320 show_cred(private_t *pri, int new, int loadonly)
2322 prcred_t cred;
2323 prpriv_t *privs;
2325 if (proc_get_cred(Pstatus(Proc)->pr_pid, &cred, 0) < 0) {
2326 perror("show_cred() - credential");
2327 (void) printf("%s\t*** Cannot get credentials\n", pri->pname);
2328 return;
2330 if ((privs = proc_get_priv(Pstatus(Proc)->pr_pid)) == NULL) {
2331 perror("show_cred() - privileges");
2332 (void) printf("%s\t*** Cannot get privileges\n", pri->pname);
2333 return;
2336 if (!loadonly && !cflag && prismember(&trace, SYS_execve)) {
2337 if (new)
2338 credentials = cred;
2339 if ((new && cred.pr_ruid != cred.pr_suid) ||
2340 cred.pr_ruid != credentials.pr_ruid ||
2341 cred.pr_suid != credentials.pr_suid)
2342 (void) printf(
2343 "%s *** SUID: ruid/euid/suid = %d / %d / %d ***\n",
2344 pri->pname,
2345 (int)cred.pr_ruid,
2346 (int)cred.pr_euid,
2347 (int)cred.pr_suid);
2348 if ((new && cred.pr_rgid != cred.pr_sgid) ||
2349 cred.pr_rgid != credentials.pr_rgid ||
2350 cred.pr_sgid != credentials.pr_sgid)
2351 (void) printf(
2352 "%s *** SGID: rgid/egid/sgid = %d / %d / %d ***\n",
2353 pri->pname,
2354 (int)cred.pr_rgid,
2355 (int)cred.pr_egid,
2356 (int)cred.pr_sgid);
2357 if (privdata != NULL && cred.pr_euid != 0) {
2358 priv_set_t *npset = getset(privs, PRIV_PERMITTED);
2359 priv_set_t *opset = getset(privdata, PRIV_PERMITTED);
2360 char *s, *t;
2361 if (!priv_issubset(npset, opset)) {
2362 /* Use the to be freed privdata as scratch */
2363 priv_inverse(opset);
2364 priv_intersect(npset, opset);
2365 s = priv_set_to_str(opset, ',', PRIV_STR_SHORT);
2366 t = priv_set_to_str(npset, ',', PRIV_STR_SHORT);
2367 (void) printf("%s *** FPRIV: P/E: %s ***\n",
2368 pri->pname,
2369 strlen(s) > strlen(t) ? t : s);
2370 free(s);
2371 free(t);
2376 if (privdata != NULL)
2377 proc_free_priv(privdata);
2378 credentials = cred;
2379 privdata = privs;
2383 * Take control of a child process.
2384 * We come here with truss_lock held.
2387 control(private_t *pri, pid_t pid)
2389 const pstatus_t *Psp;
2390 const lwpstatus_t *Lsp;
2391 pid_t childpid = 0;
2392 long flags;
2393 int rc;
2395 (void) mutex_lock(&gps->fork_lock);
2396 while (gps->fork_pid != 0)
2397 (void) cond_wait(&gps->fork_cv, &gps->fork_lock);
2398 gps->fork_pid = getpid(); /* parent pid */
2399 if ((childpid = fork()) == -1) {
2400 (void) printf("%s\t*** Cannot fork() to control process #%d\n",
2401 pri->pname, (int)pid);
2402 Flush();
2403 gps->fork_pid = 0;
2404 (void) cond_broadcast(&gps->fork_cv);
2405 (void) mutex_unlock(&gps->fork_lock);
2406 release(pri, pid);
2407 return (FALSE);
2410 if (childpid != 0) {
2412 * The parent carries on, after a brief pause.
2413 * The parent must wait until the child executes procadd(pid).
2415 while (gps->fork_pid != childpid)
2416 (void) cond_wait(&gps->fork_cv, &gps->fork_lock);
2417 gps->fork_pid = 0;
2418 (void) cond_broadcast(&gps->fork_cv);
2419 (void) mutex_unlock(&gps->fork_lock);
2420 return (FALSE);
2423 childpid = getpid();
2424 descendent = TRUE;
2425 exit_called = FALSE;
2426 Pfree(Proc); /* forget old process */
2429 * The parent process owns the shared gps->fork_lock.
2430 * The child must grab it again.
2432 (void) mutex_lock(&gps->fork_lock);
2435 * Child grabs the process and retains the tracing flags.
2437 if ((Proc = Pgrab(pid, PGRAB_RETAIN, &rc)) == NULL) {
2438 (void) fprintf(stderr,
2439 "%s: cannot control child process, pid# %d: %s\n",
2440 command, (int)pid, Pgrab_error(rc));
2441 gps->fork_pid = childpid;
2442 (void) cond_broadcast(&gps->fork_cv);
2443 (void) mutex_unlock(&gps->fork_lock);
2444 exit(2);
2447 per_proc_init();
2449 * Add ourself to the set of truss processes
2450 * and notify the parent to carry on.
2452 procadd(pid, NULL);
2453 gps->fork_pid = childpid;
2454 (void) cond_broadcast(&gps->fork_cv);
2455 (void) mutex_unlock(&gps->fork_lock);
2458 * We may have grabbed the child before it is fully stopped on exit
2459 * from fork. Wait one second (at most) for it to settle down.
2461 (void) Pwait(Proc, MILLISEC);
2462 if (Rdb_agent != NULL)
2463 Rdb_agent = Prd_agent(Proc);
2465 Psp = Pstatus(Proc);
2466 Lsp = &Psp->pr_lwp;
2467 pri->lwpstat = Lsp;
2468 data_model = Psp->pr_dmodel;
2470 make_pname(pri, 0);
2472 pri->syslast = Psp->pr_stime;
2473 pri->usrlast = Psp->pr_utime;
2475 flags = PR_FORK | PR_ASYNC;
2476 if (Dynpat != NULL)
2477 flags |= PR_BPTADJ; /* needed for x86 */
2478 (void) Psetflags(Proc, flags);
2480 return (TRUE);
2484 * Take control of an existing process.
2487 grabit(private_t *pri, proc_set_t *set)
2489 const pstatus_t *Psp;
2490 const lwpstatus_t *Lsp;
2491 int gcode;
2494 * Don't force the takeover unless the -F option was specified.
2496 if ((Proc = Pgrab(set->pid, Fflag, &gcode)) == NULL) {
2497 (void) fprintf(stderr, "%s: %s: %d\n",
2498 command, Pgrab_error(gcode), (int)set->pid);
2499 pri->lwpstat = NULL;
2500 return (FALSE);
2502 Psp = Pstatus(Proc);
2503 Lsp = &Psp->pr_lwp;
2504 pri->lwpstat = Lsp;
2506 make_pname(pri, 0);
2508 data_model = Psp->pr_dmodel;
2509 pri->syslast = Psp->pr_stime;
2510 pri->usrlast = Psp->pr_utime;
2512 if (fflag || Dynpat != NULL)
2513 (void) Psetflags(Proc, PR_FORK);
2514 else
2515 (void) Punsetflags(Proc, PR_FORK);
2516 procadd(set->pid, set->lwps);
2517 show_cred(pri, TRUE, FALSE);
2518 return (TRUE);
2522 * Release process from control.
2524 void
2525 release(private_t *pri, pid_t pid)
2528 * The process in question is the child of a traced process.
2529 * We are here to turn off the inherited tracing flags.
2531 int fd;
2532 char ctlname[100];
2533 long ctl[2];
2535 ctl[0] = PCSET;
2536 ctl[1] = PR_RLC;
2538 /* process is freshly forked, no need for exclusive open */
2539 (void) sprintf(ctlname, "/proc/%d/ctl", (int)pid);
2540 if ((fd = open(ctlname, O_WRONLY)) < 0 ||
2541 write(fd, (char *)ctl, sizeof (ctl)) < 0) {
2542 perror("release()");
2543 (void) printf(
2544 "%s\t*** Cannot release child process, pid# %d\n",
2545 pri->pname, (int)pid);
2546 Flush();
2548 if (fd >= 0) /* run-on-last-close sets the process running */
2549 (void) close(fd);
2552 void
2553 intr(int sig)
2556 * SIGUSR1 is special. It is used by one truss process to tell
2557 * another truss process to release its controlled process.
2558 * SIGUSR2 is also special. It is used to wake up threads waiting
2559 * for a victim lwp to stop after an event that will leave the
2560 * process hung (stopped and abandoned) has occurred.
2562 if (sig == SIGUSR1) {
2563 sigusr1 = TRUE;
2564 } else if (sig == SIGUSR2) {
2565 void *value;
2566 private_t *pri;
2567 struct ps_lwphandle *Lwp;
2569 if (thr_getspecific(private_key, &value) == 0 &&
2570 (pri = value) != NULL &&
2571 (Lwp = pri->Lwp) != NULL)
2572 (void) Lstop(Lwp, MILLISEC / 10);
2573 } else {
2574 interrupt = sig;
2578 void
2579 errmsg(const char *s, const char *q)
2581 char msg[512];
2583 if (s || q) {
2584 msg[0] = '\0';
2585 if (command) {
2586 (void) strcpy(msg, command);
2587 (void) strcat(msg, ": ");
2589 if (s)
2590 (void) strcat(msg, s);
2591 if (q)
2592 (void) strcat(msg, q);
2593 (void) strcat(msg, "\n");
2594 (void) write(2, msg, (size_t)strlen(msg));
2598 void
2599 abend(const char *s, const char *q)
2601 (void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL);
2602 if (Proc) {
2603 Flush();
2604 errmsg(s, q);
2605 clear_breakpoints();
2606 (void) Punsetflags(Proc, PR_ASYNC);
2607 Prelease(Proc, created? PRELEASE_KILL : PRELEASE_CLEAR);
2608 procdel();
2609 (void) wait4all();
2610 } else {
2611 errmsg(s, q);
2613 exit(2);
2617 * Allocate memory.
2618 * If allocation fails then print a message and abort.
2620 void *
2621 my_realloc(void *buf, size_t size, const char *msg)
2623 if ((buf = realloc(buf, size)) == NULL) {
2624 if (msg != NULL)
2625 abend("cannot allocate ", msg);
2626 else
2627 abend("memory allocation failure", NULL);
2630 return (buf);
2633 void *
2634 my_calloc(size_t nelem, size_t elsize, const char *msg)
2636 void *buf = NULL;
2638 if ((buf = calloc(nelem, elsize)) == NULL) {
2639 if (msg != NULL)
2640 abend("cannot allocate ", msg);
2641 else
2642 abend("memory allocation failure", NULL);
2645 return (buf);
2648 void *
2649 my_malloc(size_t size, const char *msg)
2651 return (my_realloc(NULL, size, msg));
2655 wait4all()
2657 int i;
2658 pid_t pid;
2659 int rc = 0;
2660 int status;
2662 for (i = 0; i < 10; i++) {
2663 while ((pid = wait(&status)) != -1) {
2664 /* return exit() code of the created process */
2665 if (pid == created) {
2666 if (WIFEXITED(status))
2667 rc = WEXITSTATUS(status);
2668 else
2669 rc |= 0x80; /* +128 to indicate sig */
2672 if (errno != EINTR && errno != ERESTART)
2673 break;
2676 if (i >= 10) /* repeated interrupts */
2677 rc = 2;
2679 return (rc);
2682 void
2683 letgo(private_t *pri)
2685 (void) printf("%s\t*** process otherwise traced, releasing ...\n",
2686 pri->pname);
2690 * Test for empty set.
2691 * support routine used by isemptyset() macro.
2694 is_empty(const uint32_t *sp, /* pointer to set (array of int32's) */
2695 size_t n) /* number of int32's in set */
2697 if (n) {
2698 do {
2699 if (*sp++)
2700 return (FALSE);
2701 } while (--n);
2704 return (TRUE);
2708 * OR the second set into the first.
2709 * The sets must be the same size.
2711 void
2712 or_set(uint32_t *sp1, const uint32_t *sp2, size_t n)
2714 if (n) {
2715 do {
2716 *sp1++ |= *sp2++;
2717 } while (--n);