dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / truss / main.c
blob8fc09ddf2a39b2485d28e69ff34a9d3d8dc86130
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_openat64);
679 praddset(&traceeven, SYS_open);
680 praddset(&traceeven, SYS_open64);
681 praddset(&traceeven, SYS_vfork);
682 praddset(&traceeven, SYS_forksys);
684 /* for I/O buffer dumps, force tracing of read()s and write()s */
685 if (!isemptyset(&readfd)) {
686 praddset(&traceeven, SYS_read);
687 praddset(&traceeven, SYS_readv);
688 praddset(&traceeven, SYS_pread);
689 praddset(&traceeven, SYS_pread64);
690 praddset(&traceeven, SYS_recv);
691 praddset(&traceeven, SYS_recvfrom);
692 praddset(&traceeven, SYS_recvmsg);
694 if (!isemptyset(&writefd)) {
695 praddset(&traceeven, SYS_write);
696 praddset(&traceeven, SYS_writev);
697 praddset(&traceeven, SYS_pwrite);
698 praddset(&traceeven, SYS_pwrite64);
699 praddset(&traceeven, SYS_send);
700 praddset(&traceeven, SYS_sendto);
701 praddset(&traceeven, SYS_sendmsg);
704 if (cflag || Eflag) {
705 Psetsysentry(Proc, &traceeven);
707 Psetsysexit(Proc, &traceeven);
709 /* special case -- cannot trace sysexit because context is changed */
710 if (prismember(&trace, SYS_context)) {
711 (void) Psysentry(Proc, SYS_context, TRUE);
712 (void) Psysexit(Proc, SYS_context, FALSE);
713 prdelset(&traceeven, SYS_context);
716 /* special case -- trace exec() on entry to get the args */
717 (void) Psysentry(Proc, SYS_execve, TRUE);
719 /* special case -- sysexit never reached */
720 (void) Psysentry(Proc, SYS_exit, TRUE);
721 (void) Psysentry(Proc, SYS_lwp_exit, TRUE);
722 (void) Psysexit(Proc, SYS_exit, FALSE);
723 (void) Psysexit(Proc, SYS_lwp_exit, FALSE);
725 Psetsignal(Proc, &signals); /* trace these signals */
726 Psetfault(Proc, &faults); /* trace these faults */
728 /* for function call tracing */
729 if (Dynpat != NULL) {
730 /* trace these regardless, to deal with function calls */
731 (void) Pfault(Proc, FLTBPT, TRUE);
732 (void) Pfault(Proc, FLTTRACE, TRUE);
734 /* needed for x86 */
735 (void) Psetflags(Proc, PR_BPTADJ);
738 * Find functions and set breakpoints on grabbed process.
739 * A process stopped on exec() gets its breakpoints set below.
741 if ((Lsp->pr_why != PR_SYSENTRY &&
742 Lsp->pr_why != PR_SYSEXIT) ||
743 Lsp->pr_what != SYS_execve) {
744 establish_breakpoints();
745 establish_stacks();
750 * Use asynchronous-stop for multithreaded truss.
751 * truss runs one lwp for each lwp in the target process.
753 (void) Psetflags(Proc, PR_ASYNC);
755 /* flush out all tracing flags now. */
756 Psync(Proc);
759 * If we grabbed a running process, set it running again.
760 * Since we are tracing lwp_create() and lwp_exit(), the
761 * lwps will not change in the process until we create all
762 * of the truss worker threads.
763 * We leave a created process stopped so its exec() can be reported.
765 first = created? FALSE : TRUE;
766 if (!created &&
767 ((Pstate(Proc) == PS_STOP && Lsp->pr_why == PR_REQUESTED) ||
768 (Lsp->pr_flags & PR_DSTOP)))
769 first = FALSE;
771 main_thread(first);
772 return (0);
776 * Called from main() and from control() after fork().
778 void
779 main_thread(int first)
781 private_t *pri = get_private();
782 struct tms tms;
783 int flags;
784 int retc;
785 int i;
786 int count;
789 * Block all signals in the main thread.
790 * Some worker thread will receive signals.
792 (void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL);
795 * If we are dealing with a previously hung process,
796 * arrange not to leave it hung on the same system call.
798 primary_lwp = (first && Pstate(Proc) == PS_STOP)?
799 Pstatus(Proc)->pr_lwp.pr_lwpid : 0;
802 * Create worker threads to match the lwps in the target process.
804 truss_nlwp = 0;
805 truss_maxlwp = 1;
806 truss_lwpid = my_realloc(truss_lwpid, sizeof (lwpid_t), NULL);
807 truss_lwpid[0] = 0;
808 count = 0;
809 (void) Plwp_iter(Proc, create_thread, &count);
811 if (count == 0) {
812 (void) printf("(Warning: no matching active LWPs found, "
813 "waiting)\n");
814 Flush();
818 * Set all of the truss worker threads running now.
820 (void) mutex_lock(&truss_lock);
821 for (i = 0; i < truss_maxlwp; i++) {
822 if (truss_lwpid[i])
823 (void) thr_continue(truss_lwpid[i]);
825 (void) mutex_unlock(&truss_lock);
828 * Wait until all worker threads terminate.
830 while (thr_join(0, NULL, NULL) == 0)
831 continue;
833 (void) Punsetflags(Proc, PR_ASYNC);
834 Psync(Proc);
835 if (sigusr1)
836 letgo(pri);
837 flags = PRELEASE_CLEAR;
838 if (leave_hung)
839 flags |= PRELEASE_HANG;
840 Prelease(Proc, flags);
842 procdel();
843 retc = (leave_hung? 0 : wait4all());
845 if (!descendent) {
846 interrupt = 0; /* another interrupt kills the report */
847 if (cflag) {
848 if (fflag)
849 file_to_parent();
850 report(pri, times(&tms) - starttime);
852 } else if (cflag && fflag) {
853 child_to_file();
856 exit(retc); /* exit with exit status of created process, else 0 */
859 void *
860 worker_thread(void *arg)
862 struct ps_lwphandle *Lwp = (struct ps_lwphandle *)arg;
863 const pstatus_t *Psp = Pstatus(Proc);
864 const lwpstatus_t *Lsp = Lstatus(Lwp);
865 struct syscount *scp;
866 lwpid_t who = Lsp->pr_lwpid;
867 int first = (who == primary_lwp);
868 private_t *pri = get_private();
869 int req_flag = 0;
870 int leave_it_hung = FALSE;
871 int reset_traps = FALSE;
872 int gcode;
873 int what;
874 int ow_in_effect = 0;
875 long ow_syscall = 0;
876 long ow_subcode = 0;
877 char *ow_string = NULL;
878 sysset_t full_set;
879 sysset_t running_set;
880 int dotrace = lwptrace(Psp->pr_pid, Lsp->pr_lwpid);
882 pri->Lwp = Lwp;
883 pri->lwpstat = Lsp;
884 pri->syslast = Lsp->pr_stime;
885 pri->usrlast = Lsp->pr_utime;
886 make_pname(pri, 0);
888 prfillset(&full_set);
890 /* we were created with all signals blocked; unblock them */
891 (void) thr_sigsetmask(SIG_SETMASK, &emptyset, NULL);
894 * Run this loop until the victim lwp terminates or we receive
895 * a termination condition (leave_hung | interrupt | sigusr1).
897 for (;;) {
898 if (interrupt | sigusr1) {
899 (void) Lstop(Lwp, MILLISEC);
900 if (Lstate(Lwp) == PS_RUN)
901 break;
903 if (Lstate(Lwp) == PS_RUN) {
904 /* millisecond timeout is for sleeping syscalls */
905 uint_t tout = (iflag || req_flag)? 0 : MILLISEC;
908 * If we are to leave this lwp stopped in sympathy
909 * with another lwp that has been left hung, or if
910 * we have been interrupted or instructed to release
911 * our victim process, and this lwp is stopped but
912 * not on an event of interest to /proc, then just
913 * leave it in that state.
915 if ((leave_hung | interrupt | sigusr1) &&
916 (Lsp->pr_flags & (PR_STOPPED|PR_ISTOP))
917 == PR_STOPPED)
918 break;
920 (void) Lwait(Lwp, tout);
921 if (Lstate(Lwp) == PS_RUN &&
922 tout != 0 && !(interrupt | sigusr1)) {
923 (void) mutex_lock(&truss_lock);
924 if ((Lsp->pr_flags & PR_STOPPED) &&
925 Lsp->pr_why == PR_JOBCONTROL)
926 req_flag = jobcontrol(pri, dotrace);
927 else
928 req_flag = requested(pri, req_flag,
929 dotrace);
930 (void) mutex_unlock(&truss_lock);
932 continue;
934 data_model = Psp->pr_dmodel;
935 if (Lstate(Lwp) == PS_UNDEAD)
936 break;
937 if (Lstate(Lwp) == PS_LOST) { /* we lost control */
939 * After exec(), only one LWP remains in the process.
940 * /proc makes the thread following that LWP receive
941 * EAGAIN (PS_LOST) if the program being exec()ed
942 * is a set-id program. Every other controlling
943 * thread receives ENOENT (because its LWP vanished).
944 * We are the controlling thread for the exec()ing LWP.
945 * We must wait until all of our siblings terminate
946 * before attempting to reopen the process.
948 (void) mutex_lock(&truss_lock);
949 while (truss_nlwp > 1)
950 (void) cond_wait(&truss_cv, &truss_lock);
951 if (Preopen(Proc) == 0) { /* we got control back */
953 * We have to free and re-grab the LWP.
954 * The process is guaranteed to be at exit
955 * from exec() or execve() and have only
956 * one LWP, namely this one, and the LWP
957 * is guaranteed to have lwpid == 1.
958 * This "cannot fail".
960 who = 1;
961 Lfree(Lwp);
962 pri->Lwp = Lwp =
963 Lgrab(Proc, who, &gcode);
964 if (Lwp == NULL)
965 abend("Lgrab error: ",
966 Lgrab_error(gcode));
967 pri->lwpstat = Lsp = Lstatus(Lwp);
968 (void) mutex_unlock(&truss_lock);
969 continue;
972 /* we really lost it */
973 if (pri->exec_string && *pri->exec_string) {
974 if (pri->exec_pname[0] != '\0')
975 (void) fputs(pri->exec_pname, stdout);
976 timestamp(pri);
977 (void) fputs(pri->exec_string, stdout);
978 (void) fputc('\n', stdout);
979 } else if (pri->length) {
980 (void) fputc('\n', stdout);
982 if (pri->sys_valid)
983 (void) printf(
984 "%s\t*** cannot trace across exec() of %s ***\n",
985 pri->pname, pri->sys_path);
986 else
987 (void) printf(
988 "%s\t*** lost control of process ***\n",
989 pri->pname);
990 pri->length = 0;
991 Flush();
992 (void) mutex_unlock(&truss_lock);
993 break;
995 if (Lstate(Lwp) != PS_STOP) {
996 (void) fprintf(stderr,
997 "%s: state = %d\n", command, Lstate(Lwp));
998 abend(pri->pname, "uncaught status of subject lwp");
1001 make_pname(pri, 0);
1003 (void) mutex_lock(&truss_lock);
1005 what = Lsp->pr_what;
1006 req_flag = 0;
1008 switch (Lsp->pr_why) {
1009 case PR_REQUESTED:
1010 break;
1011 case PR_SIGNALLED:
1012 req_flag = signalled(pri, req_flag, dotrace);
1013 if (Sflag && !first && prismember(&sighang, what))
1014 leave_it_hung = TRUE;
1015 break;
1016 case PR_FAULTED:
1017 if (what == FLTBPT) {
1018 int rval;
1020 (void) Pstop(Proc, 0);
1021 rval = function_trace(pri, first, 0, dotrace);
1022 if (rval == 1)
1023 leave_it_hung = TRUE;
1024 if (rval >= 0)
1025 break;
1027 if (faulted(pri, dotrace) &&
1028 Mflag && !first && prismember(&flthang, what))
1029 leave_it_hung = TRUE;
1030 break;
1031 case PR_JOBCONTROL: /* can't happen except first time */
1032 req_flag = jobcontrol(pri, dotrace);
1033 break;
1034 case PR_SYSENTRY:
1035 /* protect ourself from operating system error */
1036 if (what <= 0 || what > PRMAXSYS)
1037 what = PRMAXSYS;
1038 pri->length = 0;
1040 * ow_in_effect checks to see whether or not we
1041 * are attempting to quantify the time spent in
1042 * a one way system call. This is necessary as
1043 * some system calls never return, yet it is desireable
1044 * to determine how much time the traced process
1045 * spends in these calls. To do this, a one way
1046 * flag is set on SYSENTRY when the call is recieved.
1047 * After this, the call mask for the SYSENTRY events
1048 * is filled so that the traced process will stop
1049 * on the entry to the very next system call.
1050 * This appears to the the best way to determine
1051 * system time elapsed between a one way system call.
1052 * Once the next call occurs, values that have been
1053 * stashed are used to record the correct syscall
1054 * and time, and the SYSENTRY event mask is restored
1055 * so that the traced process may continue.
1057 if (dotrace && ow_in_effect) {
1058 if (cflag) {
1059 (void) mutex_lock(&count_lock);
1060 scp = Cp->syscount[ow_syscall];
1061 if (ow_subcode != -1)
1062 scp += ow_subcode;
1063 scp->count++;
1064 accumulate(&scp->stime,
1065 &Lsp->pr_stime, &pri->syslast);
1066 accumulate(&Cp->usrtotal,
1067 &Lsp->pr_utime, &pri->usrlast);
1068 pri->syslast = Lsp->pr_stime;
1069 pri->usrlast = Lsp->pr_utime;
1070 (void) mutex_unlock(&count_lock);
1071 } else if (Eflag) {
1072 putpname(pri);
1073 timestamp(pri);
1074 (void) printf("%s\n", ow_string);
1075 free(ow_string);
1076 ow_string = NULL;
1077 pri->syslast = Lsp->pr_stime;
1079 ow_in_effect = 0;
1080 Psetsysentry(Proc, &running_set);
1084 * Special cases. Most syscalls are traced on exit.
1086 switch (what) {
1087 case SYS_exit: /* exit() */
1088 case SYS_lwp_exit: /* lwp_exit() */
1089 case SYS_context: /* [get|set]context() */
1090 if (dotrace && cflag &&
1091 prismember(&trace, what)) {
1092 ow_in_effect = 1;
1093 ow_syscall = what;
1094 ow_subcode = getsubcode(pri);
1095 pri->syslast = Lsp->pr_stime;
1096 running_set =
1097 (Pstatus(Proc))->pr_sysentry;
1098 Psetsysentry(Proc, &full_set);
1099 } else if (dotrace && Eflag &&
1100 prismember(&trace, what)) {
1101 (void) sysentry(pri, dotrace);
1102 ow_in_effect = 1;
1103 ow_string = my_malloc(
1104 strlen(pri->sys_string) + 1, NULL);
1105 (void) strcpy(ow_string,
1106 pri->sys_string);
1107 running_set =
1108 (Pstatus(Proc))->pr_sysentry;
1109 Psetsysentry(Proc, &full_set);
1110 pri->syslast = Lsp->pr_stime;
1111 } else if (dotrace &&
1112 prismember(&trace, what)) {
1113 (void) sysentry(pri, dotrace);
1114 putpname(pri);
1115 timestamp(pri);
1116 pri->length +=
1117 printf("%s\n", pri->sys_string);
1118 Flush();
1120 pri->sys_leng = 0;
1121 *pri->sys_string = '\0';
1123 if (what == SYS_exit)
1124 exit_called = TRUE;
1125 break;
1126 case SYS_execve:
1127 show_cred(pri, FALSE, TRUE);
1128 (void) sysentry(pri, dotrace);
1129 if (dotrace && !cflag &&
1130 prismember(&trace, what)) {
1131 pri->exec_string =
1132 my_realloc(pri->exec_string,
1133 strlen(pri->sys_string) + 1,
1134 NULL);
1135 (void) strcpy(pri->exec_pname,
1136 pri->pname);
1137 (void) strcpy(pri->exec_string,
1138 pri->sys_string);
1139 pri->length += strlen(pri->sys_string);
1140 pri->exec_lwpid = Lsp->pr_lwpid;
1142 pri->sys_leng = 0;
1143 *pri->sys_string = '\0';
1144 break;
1145 default:
1146 if (dotrace && (cflag || Eflag) &&
1147 prismember(&trace, what)) {
1148 pri->syslast = Lsp->pr_stime;
1150 break;
1152 if (dotrace && Tflag && !first &&
1153 (prismember(&syshang, what) ||
1154 (exit_called && prismember(&syshang, SYS_exit))))
1155 leave_it_hung = TRUE;
1156 break;
1157 case PR_SYSEXIT:
1158 /* check for write open of a /proc file */
1159 if (what == SYS_openat || what == SYS_openat64 ||
1160 what == SYS_open || what == SYS_open64) {
1161 int readonly;
1163 (void) sysentry(pri, dotrace);
1164 pri->Errno = Lsp->pr_errno;
1165 pri->ErrPriv = Lsp->pr_errpriv;
1166 readonly =
1167 ((what == SYS_openat ||
1168 what == SYS_openat64) &&
1169 pri->sys_nargs > 2 &&
1170 (pri->sys_args[2]&0x3) == O_RDONLY) ||
1171 ((what == SYS_open ||
1172 what == SYS_open64) &&
1173 pri->sys_nargs > 1 &&
1174 (pri->sys_args[1]&0x3) == O_RDONLY);
1175 if ((pri->Errno == 0 || pri->Errno == EBUSY) &&
1176 pri->sys_valid && !readonly) {
1177 int rv = checkproc(pri);
1178 if (rv == 1 && Fflag != PGRAB_FORCE) {
1180 * The process opened itself
1181 * and no -F flag was specified.
1182 * Just print the open() call
1183 * and let go of the process.
1185 if (dotrace && !cflag &&
1186 prismember(&trace, what)) {
1187 putpname(pri);
1188 timestamp(pri);
1189 (void) printf("%s\n",
1190 pri->sys_string);
1191 Flush();
1193 sigusr1 = TRUE;
1194 (void) mutex_unlock(
1195 &truss_lock);
1196 goto out;
1198 if (rv == 2) {
1200 * Process opened someone else.
1201 * The open is being reissued.
1202 * Don't report this one.
1204 pri->sys_leng = 0;
1205 *pri->sys_string = '\0';
1206 pri->sys_nargs = 0;
1207 break;
1211 if (what == SYS_execve && pri->Errno == 0) {
1213 * Refresh the data model on exec() in case it
1214 * is different from the parent. Lwait()
1215 * doesn't update process-wide status, so we
1216 * have to explicitly call Pstopstatus() to get
1217 * the new state.
1219 (void) Pstopstatus(Proc, PCNULL, 0);
1220 data_model = Psp->pr_dmodel;
1222 if (sysexit(pri, dotrace))
1223 Flush();
1224 if (what == SYS_lwp_create && pri->Rval1 != 0) {
1225 struct ps_lwphandle *new_Lwp;
1226 lwpid_t lwpid;
1228 if ((new_Lwp = grab_lwp(pri->Rval1)) != NULL) {
1229 (void) thr_sigsetmask(SIG_SETMASK,
1230 &fillset, NULL);
1231 if (thr_create(NULL, 0, worker_thread,
1232 new_Lwp, THR_BOUND | THR_SUSPENDED,
1233 &lwpid) != 0)
1234 abend("cannot create lwp ",
1235 "to follow child lwp");
1236 insert_lwpid(lwpid);
1237 (void) thr_continue(lwpid);
1238 (void) thr_sigsetmask(SIG_SETMASK,
1239 &emptyset, NULL);
1242 pri->sys_nargs = 0;
1243 if (dotrace && Tflag && !first &&
1244 prismember(&syshang, what))
1245 leave_it_hung = TRUE;
1246 if (what == SYS_execve && pri->Errno == 0) {
1247 is_vfork_child = FALSE;
1248 reset_breakpoints();
1250 * exec() resets the calling LWP's lwpid to 1.
1251 * If the LWP has changed its lwpid, then
1252 * we have to free and re-grab the LWP
1253 * in order to keep libproc consistent.
1254 * This "cannot fail".
1256 if (who != Lsp->pr_lwpid) {
1258 * We must wait for all of our
1259 * siblings to terminate.
1261 while (truss_nlwp > 1)
1262 (void) cond_wait(&truss_cv,
1263 &truss_lock);
1264 who = Lsp->pr_lwpid;
1265 Lfree(Lwp);
1266 pri->Lwp = Lwp =
1267 Lgrab(Proc, who, &gcode);
1268 if (Lwp == NULL)
1269 abend("Lgrab error: ",
1270 Lgrab_error(gcode));
1271 pri->lwpstat = Lsp = Lstatus(Lwp);
1274 break;
1275 default:
1276 req_flag = 0;
1277 (void) fprintf(stderr,
1278 "unknown reason for stopping: %d/%d\n",
1279 Lsp->pr_why, what);
1280 abend(NULL, NULL);
1283 if (pri->child) { /* controlled process fork()ed */
1284 if (fflag || Dynpat != NULL) {
1285 if (Lsp->pr_why == PR_SYSEXIT &&
1286 (Lsp->pr_what == SYS_vfork ||
1287 (Lsp->pr_what == SYS_forksys &&
1288 Lsp->pr_sysarg[0] == 2))) {
1289 is_vfork_child = TRUE;
1290 (void) Pstop(Proc, 0);
1292 if (control(pri, pri->child)) {
1293 (void) mutex_unlock(&truss_lock);
1294 pri->child = 0;
1295 if (!fflag) {
1297 * If this is vfork(), then
1298 * this clears the breakpoints
1299 * in the parent's address space
1300 * as well as in the child's.
1302 clear_breakpoints();
1303 Prelease(Proc, PRELEASE_CLEAR);
1304 _exit(0);
1306 main_thread(FALSE);
1307 /* NOTREACHED */
1311 * Here, we are still the parent truss.
1312 * If the child messes with the breakpoints and
1313 * this is vfork(), we have to set them again.
1315 if (Dynpat != NULL && is_vfork_child && !fflag)
1316 reset_traps = TRUE;
1317 is_vfork_child = FALSE;
1319 pri->child = 0;
1322 if (leave_it_hung) {
1323 (void) mutex_unlock(&truss_lock);
1324 break;
1327 if (reset_traps) {
1329 * To recover from vfork, we must catch the lwp
1330 * that issued the vfork() when it returns to user
1331 * level, with all other lwps remaining stopped.
1332 * For this purpose, we have directed all lwps to
1333 * stop and we now set the vfork()ing lwp running
1334 * with the PRSTEP flag. We expect to capture it
1335 * when it stops again showing PR_FAULTED/FLTTRACE.
1336 * We are holding truss_lock, so no other threads
1337 * in truss will set any other lwps in the victim
1338 * process running.
1340 reset_traps = FALSE;
1341 (void) Lsetrun(Lwp, 0, PRSTEP);
1342 do {
1343 (void) Lwait(Lwp, 0);
1344 } while (Lstate(Lwp) == PS_RUN);
1345 if (Lstate(Lwp) == PS_STOP &&
1346 Lsp->pr_why == PR_FAULTED &&
1347 Lsp->pr_what == FLTTRACE) {
1348 reestablish_traps();
1349 (void) Lsetrun(Lwp, 0, PRCFAULT|PRSTOP);
1350 } else {
1351 (void) printf("%s\t*** Expected PR_FAULTED/"
1352 "FLTTRACE stop following vfork()\n",
1353 pri->pname);
1357 if (Lstate(Lwp) == PS_STOP) {
1358 int flags = 0;
1360 if (interrupt | sigusr1) {
1361 (void) mutex_unlock(&truss_lock);
1362 break;
1365 * If we must leave this lwp hung is sympathy with
1366 * another lwp that is being left hung on purpose,
1367 * then push the state onward toward PR_REQUESTED.
1369 if (leave_hung) {
1370 if (Lsp->pr_why == PR_REQUESTED) {
1371 (void) mutex_unlock(&truss_lock);
1372 break;
1374 flags |= PRSTOP;
1376 if (Lsetrun(Lwp, 0, flags) != 0 &&
1377 Lstate(Lwp) != PS_LOST &&
1378 Lstate(Lwp) != PS_UNDEAD) {
1379 (void) mutex_unlock(&truss_lock);
1380 perror("Lsetrun");
1381 abend("cannot start subject lwp", NULL);
1382 /* NOTREACHED */
1385 first = FALSE;
1387 (void) mutex_unlock(&truss_lock);
1390 out:
1391 /* block all signals in preparation for exiting */
1392 (void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL);
1394 if (Lstate(Lwp) == PS_UNDEAD || Lstate(Lwp) == PS_LOST)
1395 (void) mutex_lock(&truss_lock);
1396 else {
1397 (void) Lstop(Lwp, MILLISEC);
1398 (void) mutex_lock(&truss_lock);
1399 if (Lstate(Lwp) == PS_STOP &&
1400 Lsp->pr_why == PR_FAULTED &&
1401 Lsp->pr_what == FLTBPT)
1402 (void) function_trace(pri, 0, 1, dotrace);
1405 if (dotrace && ow_in_effect) {
1406 if (cflag) {
1407 (void) mutex_lock(&count_lock);
1408 scp = Cp->syscount[ow_syscall];
1409 if (ow_subcode != -1)
1410 scp += ow_subcode;
1411 scp->count++;
1412 accumulate(&scp->stime,
1413 &Lsp->pr_stime, &pri->syslast);
1414 accumulate(&Cp->usrtotal,
1415 &Lsp->pr_utime, &pri->usrlast);
1416 pri->syslast = Lsp->pr_stime;
1417 pri->usrlast = Lsp->pr_utime;
1418 (void) mutex_unlock(&count_lock);
1419 } else if (Eflag) {
1420 putpname(pri);
1421 timestamp(pri);
1422 (void) printf("%s\n", ow_string);
1423 free(ow_string);
1424 ow_string = NULL;
1425 pri->syslast = Lsp->pr_stime;
1427 ow_in_effect = 0;
1428 Psetsysentry(Proc, &running_set);
1431 if (Lstate(Lwp) == PS_UNDEAD || Lstate(Lwp) == PS_LOST) {
1433 * The victim thread has exited or we lost control of
1434 * the process. Remove ourself from the list of all
1435 * truss threads and notify everyone waiting for this.
1437 lwpid_t my_id = thr_self();
1438 int i;
1440 for (i = 0; i < truss_maxlwp; i++) {
1441 if (truss_lwpid[i] == my_id) {
1442 truss_lwpid[i] = 0;
1443 break;
1446 if (--truss_nlwp != 0) {
1447 (void) cond_broadcast(&truss_cv);
1448 } else {
1450 * The last truss worker thread is terminating.
1451 * The address space is gone (UNDEAD) or is
1452 * inaccessible (LOST) so we cannot clear the
1453 * breakpoints. Just report the htable stats.
1455 report_htable_stats();
1457 } else {
1459 * The victim thread is not a zombie thread, and we have not
1460 * lost control of the process. We must have gotten here due
1461 * to (leave_hung || leave_it_hung || interrupt || sigusr1).
1462 * In these cases, we must carefully uninstrument the process
1463 * and either set it running or leave it stopped and abandoned.
1465 static int nstopped = 0;
1466 static int cleared = 0;
1468 if (leave_it_hung)
1469 leave_hung = TRUE;
1470 if ((leave_hung | interrupt | sigusr1) == 0)
1471 abend("(leave_hung | interrupt | sigusr1) == 0", NULL);
1474 * The first truss thread through here needs to instruct all
1475 * application threads to stop -- they're not necessarily
1476 * going to stop on their own.
1478 if (nstopped++ == 0)
1479 (void) Pdstop(Proc);
1482 * Notify all other worker threads about the reason
1483 * for being here (leave_hung || interrupt || sigusr1).
1485 broadcast_signals();
1488 * Once the last thread has reached this point, then and
1489 * only then is it safe to remove breakpoints and other
1490 * instrumentation. Since breakpoints are executed without
1491 * truss_lock held, a monitor thread can't exit until all
1492 * breakpoints have been removed, and we can't be sure the
1493 * procedure to execute a breakpoint won't temporarily
1494 * reinstall a breakpont. Accordingly, we need to wait
1495 * until all threads are in a known state.
1497 while (nstopped != truss_nlwp)
1498 (void) cond_wait(&truss_cv, &truss_lock);
1501 * All truss threads have reached this point.
1502 * One of them clears the breakpoints and
1503 * wakes up everybody else to finish up.
1505 if (cleared++ == 0) {
1507 * All threads should already be stopped,
1508 * but just to be safe...
1510 (void) Pstop(Proc, MILLISEC);
1511 clear_breakpoints();
1512 (void) Psysexit(Proc, SYS_vfork, FALSE);
1513 (void) Psysexit(Proc, SYS_forksys, FALSE);
1514 (void) Punsetflags(Proc, PR_FORK);
1515 Psync(Proc);
1516 fflag = 0;
1517 (void) cond_broadcast(&truss_cv);
1520 if (!leave_hung && Lstate(Lwp) == PS_STOP)
1521 (void) Lsetrun(Lwp, 0, 0);
1524 (void) Lfree(Lwp);
1525 (void) mutex_unlock(&truss_lock);
1526 return (NULL);
1530 * Give a base date for time stamps, adjusted to the
1531 * stop time of the selected (first or created) process.
1533 void
1534 setup_basetime(hrtime_t basehrtime, struct timeval *basedate)
1536 const pstatus_t *Psp = Pstatus(Proc);
1537 (void) mutex_lock(&count_lock);
1538 Cp->basetime = Psp->pr_lwp.pr_tstamp;
1539 (void) mutex_unlock(&count_lock);
1541 if ((dflag|Dflag) && !cflag) {
1542 const struct tm *ptm;
1543 const char *ptime;
1544 const char *pdst;
1545 hrtime_t delta = basehrtime -
1546 ((hrtime_t)Cp->basetime.tv_sec * NANOSEC +
1547 Cp->basetime.tv_nsec);
1549 if (delta > 0) {
1550 basedate->tv_sec -= (time_t)(delta / NANOSEC);
1551 basedate->tv_usec -= (delta % NANOSEC) / 1000;
1552 if (basedate->tv_usec < 0) {
1553 basedate->tv_sec--;
1554 basedate->tv_usec += MICROSEC;
1557 ptm = localtime(&basedate->tv_sec);
1558 ptime = asctime(ptm);
1559 if ((pdst = tzname[ptm->tm_isdst ? 1 : 0]) == NULL)
1560 pdst = "???";
1561 if (dflag) {
1562 (void) printf(
1563 "Base time stamp: %ld.%4.4ld [ %.20s%s %.4s ]\n",
1564 basedate->tv_sec, basedate->tv_usec / 100,
1565 ptime, pdst, ptime + 20);
1566 Flush();
1572 * Performs per-process initializations. If truss is following a victim
1573 * process it will fork additional truss processes to follow new processes
1574 * created. Here is where each new truss process gets its per-process data
1575 * initialized.
1578 void
1579 per_proc_init()
1581 void *pmem;
1582 struct timeval basedate;
1583 hrtime_t basehrtime;
1584 struct syscount *scp;
1585 int i;
1586 timestruc_t c_basetime;
1588 /* Make sure we only configure the basetime for the first truss proc */
1590 if (Cp == NULL) {
1591 pmem = my_malloc(sizeof (struct counts) + maxsyscalls() *
1592 sizeof (struct syscount), NULL);
1593 Cp = (struct counts *)pmem;
1594 basehrtime = gethrtime();
1595 (void) gettimeofday(&basedate, NULL);
1596 setup_basetime(basehrtime, &basedate);
1599 c_basetime = Cp->basetime;
1601 (void) memset(Cp, 0, sizeof (struct counts) + maxsyscalls() *
1602 sizeof (struct syscount));
1604 Cp->basetime = c_basetime;
1606 if (fcall_tbl != NULL)
1607 destroy_hash(fcall_tbl);
1608 fcall_tbl = init_hash(4096);
1610 (void) mutex_lock(&count_lock);
1611 scp = (struct syscount *)(Cp + 1);
1612 for (i = 0; i <= PRMAXSYS; i++) {
1613 Cp->syscount[i] = scp;
1614 scp += nsubcodes(i);
1616 (void) mutex_unlock(&count_lock);
1621 * Writes child state to a tempfile where it can be read and
1622 * accumulated by the parent process. The file descriptor is shared
1623 * among the processes. Ordering of writes does not matter, it is, however,
1624 * necessary to ensure that all writes are atomic.
1627 void
1628 child_to_file()
1630 hiter_t *itr;
1631 hentry_t *ntry;
1632 hdntry_t fentry;
1633 char *s = NULL;
1634 char *t = NULL;
1635 unsigned char *buf = NULL;
1636 size_t bufsz = 0;
1637 size_t i = 0;
1638 size_t j = 0;
1640 /* ensure that we are in fact a child process */
1641 if (!descendent)
1642 return;
1644 /* enumerate fcall_tbl (tbl locked until freed) */
1645 if (Dynpat != NULL) {
1646 itr = iterate_hash(fcall_tbl);
1648 ntry = iter_next(itr);
1649 while (ntry != NULL) {
1650 fentry.type = HD_hashntry;
1651 fentry.count = ntry->count;
1652 s = ntry->key;
1653 t = ntry->lib;
1654 i = strlen(s) + 1;
1655 j = strlen(t) + 1;
1656 fentry.sz_key = i;
1657 fentry.sz_lib = j;
1658 if (i + sizeof (fentry) > bufsz) {
1659 buf = my_realloc(buf, i + j + sizeof (fentry),
1660 NULL);
1661 bufsz = i + j + sizeof (fentry);
1663 (void) memcpy(buf, &fentry, sizeof (fentry));
1664 (void) strlcpy((char *)(buf + sizeof (fentry)), t, j);
1665 (void) strlcpy((char *)(buf + sizeof (fentry) + j),
1666 s, i);
1667 if (write(sfd, buf, sizeof (fentry) + i + j) == -1)
1668 abend("Error writing to tmp file", NULL);
1669 ntry = iter_next(itr);
1671 iter_free(itr);
1674 /* Now write the count/syscount structs down */
1675 bufsz = sizeof (fentry) + (sizeof (struct counts) + maxsyscalls() *
1676 sizeof (struct syscount));
1677 buf = my_realloc(buf, bufsz, NULL);
1678 fentry.type = HD_cts_syscts;
1679 fentry.count = 0; /* undefined, really */
1680 fentry.sz_key = bufsz - sizeof (fentry);
1681 fentry.sz_lib = 0; /* also undefined */
1682 (void) memcpy(buf, &fentry, sizeof (fentry));
1683 (void) memcpy((char *)(buf + sizeof (fentry)), Cp,
1684 bufsz - sizeof (fentry));
1685 if (write(sfd, buf, bufsz) == -1)
1686 abend("Error writing cts/syscts to tmpfile", NULL);
1688 free(buf);
1692 * The following reads entries from the tempfile back to the parent
1693 * so that information can be collected and summed for overall statistics.
1694 * This reads records out of the tempfile. If they are hash table entries,
1695 * the record is merged with the hash table kept by the parent process.
1696 * If the information is a struct count/struct syscount pair, they are
1697 * copied and added into the count/syscount array kept by the parent.
1700 void
1701 file_to_parent()
1703 hdntry_t ntry;
1704 char *s = NULL;
1705 char *t = NULL;
1706 size_t c_offset = 0;
1707 size_t filesz;
1708 size_t t_strsz = 0;
1709 size_t s_strsz = 0;
1710 struct stat fsi;
1712 if (descendent)
1713 return;
1715 if (fstat(sfd, &fsi) == -1)
1716 abend("Error stat-ing tempfile", NULL);
1717 filesz = fsi.st_size;
1719 while (c_offset < filesz) {
1720 /* first get hdntry */
1721 if (pread(sfd, &ntry, sizeof (hdntry_t), c_offset) !=
1722 sizeof (hdntry_t))
1723 abend("Unable to perform full read of hdntry", NULL);
1724 c_offset += sizeof (hdntry_t);
1726 switch (ntry.type) {
1727 case HD_hashntry:
1729 /* first get lib string */
1730 if (ntry.sz_lib > t_strsz) {
1731 t = my_realloc(t, ntry.sz_lib, NULL);
1732 t_strsz = ntry.sz_lib;
1735 (void) memset(t, 0, t_strsz);
1737 /* now actually get the string */
1738 if (pread(sfd, t, ntry.sz_lib, c_offset) != ntry.sz_lib)
1739 abend("Unable to perform full read of lib str",
1740 NULL);
1741 c_offset += ntry.sz_lib;
1743 /* now get key string */
1745 if (ntry.sz_key > s_strsz) {
1746 s = my_realloc(s, ntry.sz_key, NULL);
1747 s_strsz = ntry.sz_key;
1749 (void) memset(s, 0, s_strsz);
1750 if (pread(sfd, s, ntry.sz_key, c_offset) != ntry.sz_key)
1751 abend("Unable to perform full read of key str",
1752 NULL);
1753 c_offset += ntry.sz_key;
1755 add_fcall(fcall_tbl, t, s, ntry.count);
1756 break;
1758 case HD_cts_syscts:
1760 struct counts *ncp;
1761 size_t bfsz = sizeof (struct counts) + maxsyscalls()
1762 * sizeof (struct syscount);
1763 int i;
1764 struct syscount *sscp;
1766 if (ntry.sz_key != bfsz)
1767 abend("cts/syscts size does not sanity check",
1768 NULL);
1769 ncp = my_malloc(ntry.sz_key, NULL);
1771 if (pread(sfd, ncp, ntry.sz_key, c_offset) !=
1772 ntry.sz_key)
1773 abend("Unable to perform full read of cts",
1774 NULL);
1775 c_offset += ntry.sz_key;
1777 sscp = (struct syscount *)(ncp + 1);
1779 (void) mutex_lock(&count_lock);
1781 Cp->usrtotal.tv_sec += ncp->usrtotal.tv_sec;
1782 Cp->usrtotal.tv_nsec += ncp->usrtotal.tv_nsec;
1783 if (Cp->usrtotal.tv_nsec >= NANOSEC) {
1784 Cp->usrtotal.tv_nsec -= NANOSEC;
1785 Cp->usrtotal.tv_sec++;
1787 for (i = 0; i <= PRMAXSYS; i++) {
1788 ncp->syscount[i] = sscp;
1789 sscp += nsubcodes(i);
1792 for (i = 0; i <= PRMAXFAULT; i++) {
1793 Cp->fltcount[i] += ncp->fltcount[i];
1796 for (i = 0; i <= PRMAXSIG; i++) {
1797 Cp->sigcount[i] += ncp->sigcount[i];
1800 for (i = 0; i <= PRMAXSYS; i++) {
1801 struct syscount *scp = Cp->syscount[i];
1802 struct syscount *nscp = ncp->syscount[i];
1803 int n = nsubcodes(i);
1804 int subcode;
1806 for (subcode = 0; subcode < n; subcode++,
1807 scp++, nscp++) {
1808 scp->count += nscp->count;
1809 scp->error += nscp->error;
1810 scp->stime.tv_sec += nscp->stime.tv_sec;
1811 scp->stime.tv_nsec +=
1812 nscp->stime.tv_nsec;
1813 if (scp->stime.tv_nsec >= NANOSEC) {
1814 scp->stime.tv_nsec -= NANOSEC;
1815 scp->stime.tv_sec++;
1819 (void) mutex_unlock(&count_lock);
1820 free(ncp);
1821 break;
1823 default:
1825 abend("Unknown file entry type encountered", NULL);
1826 break;
1830 if (fstat(sfd, &fsi) == -1)
1831 abend("Error stat-ing tempfile", NULL);
1832 filesz = fsi.st_size;
1834 free(s);
1835 free(t);
1838 void
1839 make_pname(private_t *pri, id_t tid)
1841 if (!cflag) {
1842 int ff = (fflag || ngrab > 1);
1843 int lf = (lflag | tid | (Thr_agent != NULL) | (truss_nlwp > 1));
1844 pid_t pid = Pstatus(Proc)->pr_pid;
1845 id_t lwpid = pri->lwpstat->pr_lwpid;
1847 if (ff != pri->pparam.ff ||
1848 lf != pri->pparam.lf ||
1849 pid != pri->pparam.pid ||
1850 lwpid != pri->pparam.lwpid ||
1851 tid != pri->pparam.tid) {
1852 char *s = pri->pname;
1854 if (ff)
1855 s += sprintf(s, "%d", (int)pid);
1856 if (lf)
1857 s += sprintf(s, "/%d", (int)lwpid);
1858 if (tid)
1859 s += sprintf(s, "@%d", (int)tid);
1860 if (ff || lf)
1861 *s++ = ':', *s++ = '\t';
1862 if (ff && lf && s < pri->pname + 9)
1863 *s++ = '\t';
1864 *s = '\0';
1865 pri->pparam.ff = ff;
1866 pri->pparam.lf = lf;
1867 pri->pparam.pid = pid;
1868 pri->pparam.lwpid = lwpid;
1869 pri->pparam.tid = tid;
1875 * Print the pri->pname[] string, if any.
1877 void
1878 putpname(private_t *pri)
1880 if (pri->pname[0])
1881 (void) fputs(pri->pname, stdout);
1885 * Print the timestamp, if requested (-d, -D, or -E).
1887 void
1888 timestamp(private_t *pri)
1890 const lwpstatus_t *Lsp = pri->lwpstat;
1891 int seconds;
1892 int fraction;
1894 if (!(dflag|Dflag|Eflag) || !(Lsp->pr_flags & PR_STOPPED))
1895 return;
1897 seconds = Lsp->pr_tstamp.tv_sec - Cp->basetime.tv_sec;
1898 fraction = Lsp->pr_tstamp.tv_nsec - Cp->basetime.tv_nsec;
1899 if (fraction < 0) {
1900 seconds--;
1901 fraction += NANOSEC;
1903 /* fraction in 1/10 milliseconds, rounded up */
1904 fraction = (fraction + 50000) / 100000;
1905 if (fraction >= (MILLISEC * 10)) {
1906 seconds++;
1907 fraction -= (MILLISEC * 10);
1910 if (dflag) /* time stamp */
1911 (void) printf("%2d.%4.4d\t", seconds, fraction);
1913 if (Dflag) { /* time delta */
1914 int oseconds = pri->seconds;
1915 int ofraction = pri->fraction;
1917 pri->seconds = seconds;
1918 pri->fraction = fraction;
1919 seconds -= oseconds;
1920 fraction -= ofraction;
1921 if (fraction < 0) {
1922 seconds--;
1923 fraction += (MILLISEC * 10);
1925 (void) printf("%2d.%4.4d\t", seconds, fraction);
1928 if (Eflag) {
1929 seconds = Lsp->pr_stime.tv_sec - pri->syslast.tv_sec;
1930 fraction = Lsp->pr_stime.tv_nsec - pri->syslast.tv_nsec;
1932 if (fraction < 0) {
1933 seconds--;
1934 fraction += NANOSEC;
1936 /* fraction in 1/10 milliseconds, rounded up */
1937 fraction = (fraction + 50000) / 100000;
1938 if (fraction >= (MILLISEC * 10)) {
1939 seconds++;
1940 fraction -= (MILLISEC * 10);
1942 (void) printf("%2d.%4.4d\t", seconds, fraction);
1947 * Create output file, being careful about
1948 * suid/sgid and file descriptor 0, 1, 2 issues.
1951 xcreat(char *path)
1953 int fd;
1954 int mode = 0666;
1956 if (Euid == Ruid && Egid == Rgid) /* not set-id */
1957 fd = creat(path, mode);
1958 else if (access(path, F_OK) != 0) { /* file doesn't exist */
1959 /* if directory permissions OK, create file & set ownership */
1961 char *dir;
1962 char *p;
1963 char dot[4];
1965 /* generate path for directory containing file */
1966 if ((p = strrchr(path, '/')) == NULL) { /* no '/' */
1967 p = dir = dot;
1968 *p++ = '.'; /* current directory */
1969 *p = '\0';
1970 } else if (p == path) { /* leading '/' */
1971 p = dir = dot;
1972 *p++ = '/'; /* root directory */
1973 *p = '\0';
1974 } else { /* embedded '/' */
1975 dir = path; /* directory path */
1976 *p = '\0';
1979 if (access(dir, W_OK|X_OK) != 0) {
1980 /* not writeable/searchable */
1981 *p = '/';
1982 fd = -1;
1983 } else { /* create file and set ownership correctly */
1984 *p = '/';
1985 if ((fd = creat(path, mode)) >= 0)
1986 (void) chown(path, (int)Ruid, (int)Rgid);
1988 } else if (access(path, W_OK) != 0) /* file not writeable */
1989 fd = -1;
1990 else
1991 fd = creat(path, mode);
1994 * Make sure it's not one of 0, 1, or 2.
1995 * This allows truss to work when spawned by init(1m).
1997 if (0 <= fd && fd <= 2) {
1998 int dfd = fcntl(fd, F_DUPFD, 3);
1999 (void) close(fd);
2000 fd = dfd;
2004 * Mark it close-on-exec so created processes don't inherit it.
2006 if (fd >= 0)
2007 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
2009 return (fd);
2012 void
2013 setoutput(int ofd)
2015 if (ofd < 0) {
2016 (void) close(1);
2017 (void) fcntl(2, F_DUPFD, 1);
2018 } else if (ofd != 1) {
2019 (void) close(1);
2020 (void) fcntl(ofd, F_DUPFD, 1);
2021 (void) close(ofd);
2022 /* if no stderr, make it the same file */
2023 if ((ofd = dup(2)) < 0)
2024 (void) fcntl(1, F_DUPFD, 2);
2025 else
2026 (void) close(ofd);
2031 * Accumulate time differencies: a += e - s;
2033 void
2034 accumulate(timestruc_t *ap, const timestruc_t *ep, const timestruc_t *sp)
2036 ap->tv_sec += ep->tv_sec - sp->tv_sec;
2037 ap->tv_nsec += ep->tv_nsec - sp->tv_nsec;
2038 if (ap->tv_nsec >= NANOSEC) {
2039 ap->tv_nsec -= NANOSEC;
2040 ap->tv_sec++;
2041 } else if (ap->tv_nsec < 0) {
2042 ap->tv_nsec += NANOSEC;
2043 ap->tv_sec--;
2048 lib_sort(const void *p1, const void *p2)
2050 int cmpr = 0;
2051 long i;
2052 long j;
2054 hentry_t *t1 = (hentry_t *)p1;
2055 hentry_t *t2 = (hentry_t *)p2;
2057 char *p = t1->lib;
2058 char *q = t2->lib;
2060 if ((cmpr = strcmp(p, q)) == 0) {
2061 i = t1->count;
2062 j = t2->count;
2063 if (i > j)
2064 return (-1);
2065 else if (i < j)
2066 return (1);
2067 else {
2068 p = t1->key;
2069 q = t2->key;
2070 return (strcmp(p, q));
2072 } else
2073 return (cmpr);
2076 void
2077 report(private_t *pri, time_t lapse) /* elapsed time, clock ticks */
2079 int i;
2080 long count;
2081 const char *name;
2082 long error;
2083 long total;
2084 long errtot;
2085 timestruc_t tickzero;
2086 timestruc_t ticks;
2087 timestruc_t ticktot;
2089 if (descendent)
2090 return;
2092 for (i = 0, total = 0; i <= PRMAXFAULT && !interrupt; i++) {
2093 if ((count = Cp->fltcount[i]) != 0) {
2094 if (total == 0) /* produce header */
2095 (void) printf("faults -------------\n");
2097 name = proc_fltname(i, pri->flt_name,
2098 sizeof (pri->flt_name));
2100 (void) printf("%s%s\t%4ld\n", name,
2101 (((int)strlen(name) < 8)?
2102 (const char *)"\t" : (const char *)""),
2103 count);
2104 total += count;
2107 if (total && !interrupt)
2108 (void) printf("total:\t\t%4ld\n\n", total);
2110 for (i = 0, total = 0; i <= PRMAXSIG && !interrupt; i++) {
2111 if ((count = Cp->sigcount[i]) != 0) {
2112 if (total == 0) /* produce header */
2113 (void) printf("signals ------------\n");
2114 name = signame(pri, i);
2115 (void) printf("%s%s\t%4ld\n", name,
2116 (((int)strlen(name) < 8)?
2117 (const char *)"\t" : (const char *)""),
2118 count);
2119 total += count;
2122 if (total && !interrupt)
2123 (void) printf("total:\t\t%4ld\n\n", total);
2125 if ((Dynpat != NULL) && !interrupt) {
2126 size_t elem = elements_in_table(fcall_tbl);
2127 hiter_t *itr = iterate_hash(fcall_tbl);
2128 hentry_t *tmp = iter_next(itr);
2129 hentry_t *stbl = my_malloc(elem * sizeof (hentry_t), NULL);
2130 i = 0;
2131 while ((tmp != NULL) && (i < elem)) {
2132 stbl[i].prev = tmp->prev;
2133 stbl[i].next = tmp->next;
2134 stbl[i].lib = tmp->lib;
2135 stbl[i].key = tmp->key;
2136 stbl[i].count = tmp->count;
2137 tmp = iter_next(itr);
2138 i++;
2140 qsort((void *)stbl, elem, sizeof (hentry_t),
2141 lib_sort);
2142 (void) printf(
2143 "\n%-20s %-40s %s\n", "Library:", "Function", "calls");
2144 for (i = 0; i < elem; i++) {
2145 (void) printf("%-20s %-40s %ld\n", stbl[i].lib,
2146 stbl[i].key, stbl[i].count);
2148 iter_free(itr);
2149 free(stbl);
2150 itr = NULL;
2153 if (!interrupt)
2154 (void) printf(
2155 "\nsyscall seconds calls errors\n");
2157 total = errtot = 0;
2158 tickzero.tv_sec = ticks.tv_sec = ticktot.tv_sec = 0;
2159 tickzero.tv_nsec = ticks.tv_nsec = ticktot.tv_nsec = 0;
2160 for (i = 0; i <= PRMAXSYS && !interrupt; i++) {
2161 struct syscount *scp = Cp->syscount[i];
2162 int n = nsubcodes(i);
2163 int subcode;
2165 for (subcode = 0; subcode < n; subcode++, scp++) {
2166 if ((count = scp->count) != 0 || scp->error) {
2167 (void) printf("%-19.19s ",
2168 sysname(pri, i, subcode));
2170 ticks = scp->stime;
2171 accumulate(&ticktot, &ticks, &tickzero);
2172 prtim(&ticks);
2174 (void) printf(" %7ld", count);
2175 if ((error = scp->error) != 0)
2176 (void) printf(" %7ld", error);
2177 (void) fputc('\n', stdout);
2178 total += count;
2179 errtot += error;
2184 if (!interrupt) {
2185 (void) printf(
2186 " -------- ------ ----\n");
2187 (void) printf("sys totals: ");
2188 prtim(&ticktot);
2189 (void) printf(" %7ld %6ld\n", total, errtot);
2192 if (!interrupt) {
2193 (void) printf("usr time: ");
2194 prtim(&Cp->usrtotal);
2195 (void) fputc('\n', stdout);
2198 if (!interrupt) {
2199 int hz = (int)sysconf(_SC_CLK_TCK);
2201 ticks.tv_sec = lapse / hz;
2202 ticks.tv_nsec = (lapse % hz) * (1000000000 / hz);
2203 (void) printf("elapsed: ");
2204 prtim(&ticks);
2205 (void) fputc('\n', stdout);
2209 void
2210 prtim(timestruc_t *tp)
2212 time_t sec;
2214 if ((sec = tp->tv_sec) != 0) /* whole seconds */
2215 (void) printf("%5lu", sec);
2216 else
2217 (void) printf(" ");
2219 (void) printf(".%3.3ld", tp->tv_nsec/1000000); /* fraction */
2223 * Gather process id's.
2224 * Return 0 on success, != 0 on failure.
2226 void
2227 pids(char *arg, proc_set_t *grab)
2229 pid_t pid = -1;
2230 int i;
2231 const char *lwps = NULL;
2233 if ((pid = proc_arg_xpsinfo(arg, PR_ARG_PIDS, NULL, &i, &lwps)) < 0) {
2234 (void) fprintf(stderr, "%s: cannot trace '%s': %s\n",
2235 command, arg, Pgrab_error(i));
2236 return;
2239 for (i = 0; i < ngrab; i++)
2240 if (grab[i].pid == pid) /* duplicate */
2241 break;
2243 if (i == ngrab) {
2244 grab[ngrab].pid = pid;
2245 grab[ngrab].lwps = lwps;
2246 ngrab++;
2247 } else {
2248 (void) fprintf(stderr, "%s: duplicate process-id ignored: %d\n",
2249 command, (int)pid);
2254 * Report psargs string.
2256 void
2257 psargs(private_t *pri)
2259 pid_t pid = Pstatus(Proc)->pr_pid;
2260 psinfo_t psinfo;
2262 if (proc_get_psinfo(pid, &psinfo) == 0)
2263 (void) printf("%spsargs: %.64s\n",
2264 pri->pname, psinfo.pr_psargs);
2265 else {
2266 perror("psargs()");
2267 (void) printf("%s\t*** Cannot read psinfo file for pid %d\n",
2268 pri->pname, (int)pid);
2272 char *
2273 fetchstring(private_t *pri, long addr, int maxleng)
2275 int nbyte;
2276 int leng = 0;
2277 char string[41];
2279 string[40] = '\0';
2280 if (pri->str_bsize == 0) /* initial allocation of string buffer */
2281 pri->str_buffer =
2282 my_malloc(pri->str_bsize = 16, "string buffer");
2283 *pri->str_buffer = '\0';
2285 for (nbyte = 40; nbyte == 40 && leng < maxleng; addr += 40) {
2286 if ((nbyte = Pread(Proc, string, 40, addr)) <= 0)
2287 return (leng? pri->str_buffer : NULL);
2288 if (nbyte > 0 &&
2289 (nbyte = strlen(string)) > 0) {
2290 while (leng + nbyte >= pri->str_bsize)
2291 pri->str_buffer =
2292 my_realloc(pri->str_buffer,
2293 pri->str_bsize *= 2, "string buffer");
2294 (void) strcpy(pri->str_buffer+leng, string);
2295 leng += nbyte;
2299 if (leng > maxleng)
2300 leng = maxleng;
2301 pri->str_buffer[leng] = '\0';
2303 return (pri->str_buffer);
2306 static priv_set_t *
2307 getset(prpriv_t *p, priv_ptype_t set)
2309 return ((priv_set_t *)
2310 &p->pr_sets[priv_getsetbyname(set) * p->pr_setsize]);
2313 void
2314 show_cred(private_t *pri, int new, int loadonly)
2316 prcred_t cred;
2317 prpriv_t *privs;
2319 if (proc_get_cred(Pstatus(Proc)->pr_pid, &cred, 0) < 0) {
2320 perror("show_cred() - credential");
2321 (void) printf("%s\t*** Cannot get credentials\n", pri->pname);
2322 return;
2324 if ((privs = proc_get_priv(Pstatus(Proc)->pr_pid)) == NULL) {
2325 perror("show_cred() - privileges");
2326 (void) printf("%s\t*** Cannot get privileges\n", pri->pname);
2327 return;
2330 if (!loadonly && !cflag && prismember(&trace, SYS_execve)) {
2331 if (new)
2332 credentials = cred;
2333 if ((new && cred.pr_ruid != cred.pr_suid) ||
2334 cred.pr_ruid != credentials.pr_ruid ||
2335 cred.pr_suid != credentials.pr_suid)
2336 (void) printf(
2337 "%s *** SUID: ruid/euid/suid = %d / %d / %d ***\n",
2338 pri->pname,
2339 (int)cred.pr_ruid,
2340 (int)cred.pr_euid,
2341 (int)cred.pr_suid);
2342 if ((new && cred.pr_rgid != cred.pr_sgid) ||
2343 cred.pr_rgid != credentials.pr_rgid ||
2344 cred.pr_sgid != credentials.pr_sgid)
2345 (void) printf(
2346 "%s *** SGID: rgid/egid/sgid = %d / %d / %d ***\n",
2347 pri->pname,
2348 (int)cred.pr_rgid,
2349 (int)cred.pr_egid,
2350 (int)cred.pr_sgid);
2351 if (privdata != NULL && cred.pr_euid != 0) {
2352 priv_set_t *npset = getset(privs, PRIV_PERMITTED);
2353 priv_set_t *opset = getset(privdata, PRIV_PERMITTED);
2354 char *s, *t;
2355 if (!priv_issubset(npset, opset)) {
2356 /* Use the to be freed privdata as scratch */
2357 priv_inverse(opset);
2358 priv_intersect(npset, opset);
2359 s = priv_set_to_str(opset, ',', PRIV_STR_SHORT);
2360 t = priv_set_to_str(npset, ',', PRIV_STR_SHORT);
2361 (void) printf("%s *** FPRIV: P/E: %s ***\n",
2362 pri->pname,
2363 strlen(s) > strlen(t) ? t : s);
2364 free(s);
2365 free(t);
2370 proc_free_priv(privdata);
2371 credentials = cred;
2372 privdata = privs;
2376 * Take control of a child process.
2377 * We come here with truss_lock held.
2380 control(private_t *pri, pid_t pid)
2382 const pstatus_t *Psp;
2383 const lwpstatus_t *Lsp;
2384 pid_t childpid = 0;
2385 long flags;
2386 int rc;
2388 (void) mutex_lock(&gps->fork_lock);
2389 while (gps->fork_pid != 0)
2390 (void) cond_wait(&gps->fork_cv, &gps->fork_lock);
2391 gps->fork_pid = getpid(); /* parent pid */
2392 if ((childpid = fork()) == -1) {
2393 (void) printf("%s\t*** Cannot fork() to control process #%d\n",
2394 pri->pname, (int)pid);
2395 Flush();
2396 gps->fork_pid = 0;
2397 (void) cond_broadcast(&gps->fork_cv);
2398 (void) mutex_unlock(&gps->fork_lock);
2399 release(pri, pid);
2400 return (FALSE);
2403 if (childpid != 0) {
2405 * The parent carries on, after a brief pause.
2406 * The parent must wait until the child executes procadd(pid).
2408 while (gps->fork_pid != childpid)
2409 (void) cond_wait(&gps->fork_cv, &gps->fork_lock);
2410 gps->fork_pid = 0;
2411 (void) cond_broadcast(&gps->fork_cv);
2412 (void) mutex_unlock(&gps->fork_lock);
2413 return (FALSE);
2416 childpid = getpid();
2417 descendent = TRUE;
2418 exit_called = FALSE;
2419 Pfree(Proc); /* forget old process */
2422 * The parent process owns the shared gps->fork_lock.
2423 * The child must grab it again.
2425 (void) mutex_lock(&gps->fork_lock);
2428 * Child grabs the process and retains the tracing flags.
2430 if ((Proc = Pgrab(pid, PGRAB_RETAIN, &rc)) == NULL) {
2431 (void) fprintf(stderr,
2432 "%s: cannot control child process, pid# %d: %s\n",
2433 command, (int)pid, Pgrab_error(rc));
2434 gps->fork_pid = childpid;
2435 (void) cond_broadcast(&gps->fork_cv);
2436 (void) mutex_unlock(&gps->fork_lock);
2437 exit(2);
2440 per_proc_init();
2442 * Add ourself to the set of truss processes
2443 * and notify the parent to carry on.
2445 procadd(pid, NULL);
2446 gps->fork_pid = childpid;
2447 (void) cond_broadcast(&gps->fork_cv);
2448 (void) mutex_unlock(&gps->fork_lock);
2451 * We may have grabbed the child before it is fully stopped on exit
2452 * from fork. Wait one second (at most) for it to settle down.
2454 (void) Pwait(Proc, MILLISEC);
2455 if (Rdb_agent != NULL)
2456 Rdb_agent = Prd_agent(Proc);
2458 Psp = Pstatus(Proc);
2459 Lsp = &Psp->pr_lwp;
2460 pri->lwpstat = Lsp;
2461 data_model = Psp->pr_dmodel;
2463 make_pname(pri, 0);
2465 pri->syslast = Psp->pr_stime;
2466 pri->usrlast = Psp->pr_utime;
2468 flags = PR_FORK | PR_ASYNC;
2469 if (Dynpat != NULL)
2470 flags |= PR_BPTADJ; /* needed for x86 */
2471 (void) Psetflags(Proc, flags);
2473 return (TRUE);
2477 * Take control of an existing process.
2480 grabit(private_t *pri, proc_set_t *set)
2482 const pstatus_t *Psp;
2483 const lwpstatus_t *Lsp;
2484 int gcode;
2487 * Don't force the takeover unless the -F option was specified.
2489 if ((Proc = Pgrab(set->pid, Fflag, &gcode)) == NULL) {
2490 (void) fprintf(stderr, "%s: %s: %d\n",
2491 command, Pgrab_error(gcode), (int)set->pid);
2492 pri->lwpstat = NULL;
2493 return (FALSE);
2495 Psp = Pstatus(Proc);
2496 Lsp = &Psp->pr_lwp;
2497 pri->lwpstat = Lsp;
2499 make_pname(pri, 0);
2501 data_model = Psp->pr_dmodel;
2502 pri->syslast = Psp->pr_stime;
2503 pri->usrlast = Psp->pr_utime;
2505 if (fflag || Dynpat != NULL)
2506 (void) Psetflags(Proc, PR_FORK);
2507 else
2508 (void) Punsetflags(Proc, PR_FORK);
2509 procadd(set->pid, set->lwps);
2510 show_cred(pri, TRUE, FALSE);
2511 return (TRUE);
2515 * Release process from control.
2517 void
2518 release(private_t *pri, pid_t pid)
2521 * The process in question is the child of a traced process.
2522 * We are here to turn off the inherited tracing flags.
2524 int fd;
2525 char ctlname[100];
2526 long ctl[2];
2528 ctl[0] = PCSET;
2529 ctl[1] = PR_RLC;
2531 /* process is freshly forked, no need for exclusive open */
2532 (void) sprintf(ctlname, "/proc/%d/ctl", (int)pid);
2533 if ((fd = open(ctlname, O_WRONLY)) < 0 ||
2534 write(fd, (char *)ctl, sizeof (ctl)) < 0) {
2535 perror("release()");
2536 (void) printf(
2537 "%s\t*** Cannot release child process, pid# %d\n",
2538 pri->pname, (int)pid);
2539 Flush();
2541 if (fd >= 0) /* run-on-last-close sets the process running */
2542 (void) close(fd);
2545 void
2546 intr(int sig)
2549 * SIGUSR1 is special. It is used by one truss process to tell
2550 * another truss process to release its controlled process.
2551 * SIGUSR2 is also special. It is used to wake up threads waiting
2552 * for a victim lwp to stop after an event that will leave the
2553 * process hung (stopped and abandoned) has occurred.
2555 if (sig == SIGUSR1) {
2556 sigusr1 = TRUE;
2557 } else if (sig == SIGUSR2) {
2558 void *value;
2559 private_t *pri;
2560 struct ps_lwphandle *Lwp;
2562 if (thr_getspecific(private_key, &value) == 0 &&
2563 (pri = value) != NULL &&
2564 (Lwp = pri->Lwp) != NULL)
2565 (void) Lstop(Lwp, MILLISEC / 10);
2566 } else {
2567 interrupt = sig;
2571 void
2572 errmsg(const char *s, const char *q)
2574 char msg[512];
2576 if (s || q) {
2577 msg[0] = '\0';
2578 if (command) {
2579 (void) strcpy(msg, command);
2580 (void) strcat(msg, ": ");
2582 if (s)
2583 (void) strcat(msg, s);
2584 if (q)
2585 (void) strcat(msg, q);
2586 (void) strcat(msg, "\n");
2587 (void) write(2, msg, (size_t)strlen(msg));
2591 void
2592 abend(const char *s, const char *q)
2594 (void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL);
2595 if (Proc) {
2596 Flush();
2597 errmsg(s, q);
2598 clear_breakpoints();
2599 (void) Punsetflags(Proc, PR_ASYNC);
2600 Prelease(Proc, created? PRELEASE_KILL : PRELEASE_CLEAR);
2601 procdel();
2602 (void) wait4all();
2603 } else {
2604 errmsg(s, q);
2606 exit(2);
2610 * Allocate memory.
2611 * If allocation fails then print a message and abort.
2613 void *
2614 my_realloc(void *buf, size_t size, const char *msg)
2616 if ((buf = realloc(buf, size)) == NULL) {
2617 if (msg != NULL)
2618 abend("cannot allocate ", msg);
2619 else
2620 abend("memory allocation failure", NULL);
2623 return (buf);
2626 void *
2627 my_calloc(size_t nelem, size_t elsize, const char *msg)
2629 void *buf = NULL;
2631 if ((buf = calloc(nelem, elsize)) == NULL) {
2632 if (msg != NULL)
2633 abend("cannot allocate ", msg);
2634 else
2635 abend("memory allocation failure", NULL);
2638 return (buf);
2641 void *
2642 my_malloc(size_t size, const char *msg)
2644 return (my_realloc(NULL, size, msg));
2648 wait4all()
2650 int i;
2651 pid_t pid;
2652 int rc = 0;
2653 int status;
2655 for (i = 0; i < 10; i++) {
2656 while ((pid = wait(&status)) != -1) {
2657 /* return exit() code of the created process */
2658 if (pid == created) {
2659 if (WIFEXITED(status))
2660 rc = WEXITSTATUS(status);
2661 else
2662 rc |= 0x80; /* +128 to indicate sig */
2665 if (errno != EINTR && errno != ERESTART)
2666 break;
2669 if (i >= 10) /* repeated interrupts */
2670 rc = 2;
2672 return (rc);
2675 void
2676 letgo(private_t *pri)
2678 (void) printf("%s\t*** process otherwise traced, releasing ...\n",
2679 pri->pname);
2683 * Test for empty set.
2684 * support routine used by isemptyset() macro.
2687 is_empty(const uint32_t *sp, /* pointer to set (array of int32's) */
2688 size_t n) /* number of int32's in set */
2690 if (n) {
2691 do {
2692 if (*sp++)
2693 return (FALSE);
2694 } while (--n);
2697 return (TRUE);
2701 * OR the second set into the first.
2702 * The sets must be the same size.
2704 void
2705 or_set(uint32_t *sp1, const uint32_t *sp2, size_t n)
2707 if (n) {
2708 do {
2709 *sp1++ |= *sp2++;
2710 } while (--n);