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]
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 */
30 #include <stdio_ext.h>
41 #include <sys/types.h>
43 #include <sys/times.h>
44 #include <sys/fstyp.h>
48 #include <sys/resource.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
{
66 * Function prototypes for static routines in this file.
68 void setup_basetime(hrtime_t
, struct timeval
*);
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
);
80 void letgo(private_t
*);
82 void file_to_parent();
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);
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 */
112 private_t
*pri
= NULL
;
114 if (thr_getspecific(private_key
, &value
) == 0)
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
);
127 /* destructor function for thread-private data */
129 free_private(void *value
)
131 private_t
*pri
= value
;
134 free(pri
->sys_string
);
135 free(pri
->exec_string
);
136 free(pri
->str_buffer
);
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.
146 insert_lwpid(lwpid_t lwpid
)
151 for (i
= 0; i
< truss_maxlwp
; i
++) {
152 if (truss_lwpid
[i
] == 0)
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
));
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.
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();
181 if (interrupt
&& !int_notified
) {
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
;
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,"
215 command
, who
, (int)Pstatus(Proc
)->pr_pid
,
217 interrupt
= SIGTERM
; /* post an interrupt */
224 * Iteration function called for each initial lwp in the controlled process.
228 create_thread(void *arg
, const lwpstatus_t
*Lsp
)
230 struct ps_lwphandle
*new_Lwp
;
234 if (lwptrace(Pstatus(Proc
)->pr_pid
, Lsp
->pr_lwpid
))
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
);
247 main(int argc
, char *argv
[])
258 proc_set_t
*grab
= NULL
;
259 const pstatus_t
*Psp
;
260 const lwpstatus_t
*Lsp
;
263 /* a few of these need to be initialized to 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)
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
)
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
);
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
) {
323 case 'F': /* force grabbing (no O_EXCL) */
326 case 'p': /* grab processes */
329 case 'f': /* follow children */
332 case 'c': /* don't trace, just count */
334 iflag
= TRUE
; /* implies no interruptable syscalls */
336 case 'a': /* display argument lists */
339 case 'e': /* display environments */
342 case 'i': /* don't show interruptable syscalls */
345 case 'l': /* show lwp id for each syscall */
348 case 'h': /* debugging: report hash stats */
351 case 'd': /* show time stamps */
354 case 'D': /* show time deltas */
358 Eflag
= TRUE
; /* show syscall times */
360 case 't': /* system calls to trace */
361 if (syslist(optarg
, &trace
, &tflag
))
364 case 'T': /* system calls to hang process */
365 if (syslist(optarg
, &syshang
, &Tflag
))
368 case 'v': /* verbose interpretation of syscalls */
369 if (syslist(optarg
, &verbose
, &vflag
))
372 case 'x': /* raw interpretation of syscalls */
373 if (syslist(optarg
, &rawout
, &xflag
))
376 case 's': /* signals to trace */
377 if (siglist(pri
, optarg
, &signals
, &sflag
))
380 case 'S': /* signals to hang process */
381 if (siglist(pri
, optarg
, &sighang
, &Sflag
))
384 case 'm': /* machine faults to trace */
385 if (fltlist(optarg
, &faults
, &mflag
))
388 case 'M': /* machine faults to hang process */
389 if (fltlist(optarg
, &flthang
, &Mflag
))
392 case 'u': /* user library functions to trace */
393 if (liblist(optarg
, 0))
396 case 'U': /* user library functions to hang */
397 if (liblist(optarg
, 1))
400 case 'r': /* show contents of read(fd) */
401 if (fdlist(optarg
, &readfd
))
404 case 'w': /* show contents of write(fd) */
405 if (fdlist(optarg
, &writefd
))
408 case 'o': /* output file for trace */
412 if ((ofd
= xcreat(optarg
)) < 0) {
426 /* if -a or -e was specified, force tracing of exec() */
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
);
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");
449 if (errflg
|| (argc
<= 0 && ngrab
<= 0)) {
450 (void) fprintf(stderr
,
451 "usage:\t%s [-fcaeildDEF] [-[tTvx] [!]syscalls] [-[sS] [!]signals]\\\n",
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");
460 if (argc
> 0) { /* create the controlled process */
464 Proc
= Pcreate(argv
[0], &argv
[0], &err
, path
, sizeof (path
));
468 (void) fprintf(stderr
,
469 "%s: cannot trace set-id or "
470 "unreadable object file: %s\n",
474 (void) fprintf(stderr
,
475 "%s: cannot control _LP64 "
480 (void) fprintf(stderr
,
481 "%s: cannot execute program: %s\n",
485 (void) fprintf(stderr
,
486 "%s: cannot find program: %s\n",
492 (void) fprintf(stderr
, "%s: %s\n",
493 command
, Pcreate_error(err
));
498 if (fflag
|| Dynpat
!= NULL
)
499 (void) Psetflags(Proc
, PR_FORK
);
501 (void) Punsetflags(Proc
, PR_FORK
);
505 data_model
= Psp
->pr_dmodel
;
506 created
= Psp
->pr_pid
;
508 (void) sysentry(pri
, 1);
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
;
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 */
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
),
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);
593 abend("Error creating tmpfile", NULL
);
594 if (unlink(tmps
) == -1)
595 abend("Error unlinking tmpfile", NULL
);
602 procadd(created
, NULL
);
603 show_cred(pri
, TRUE
, FALSE
);
604 } else { /* grab the specified processes */
608 while (i
< ngrab
) { /* grab first process */
609 if (grabit(pri
, &grab
[i
++])) {
619 while (i
< ngrab
) { /* grab the remainder */
620 proc_set_t
*set
= &grab
[i
++];
622 (void) mutex_lock(&truss_lock
);
625 (void) fprintf(stderr
,
626 "%s: cannot fork to control process, pid# %d\n",
627 command
, (int)set
->pid
);
630 (void) mutex_unlock(&truss_lock
);
631 continue; /* parent carries on */
633 case 0: /* child grabs process */
634 (void) mutex_unlock(&truss_lock
);
637 if (grabit(pri
, set
)) {
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).
661 if (!created
&& aflag
&& prismember(&trace
, SYS_execve
)) {
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
);
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();
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. */
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
;
767 ((Pstate(Proc
) == PS_STOP
&& Lsp
->pr_why
== PR_REQUESTED
) ||
768 (Lsp
->pr_flags
& PR_DSTOP
)))
776 * Called from main() and from control() after fork().
779 main_thread(int first
)
781 private_t
*pri
= get_private();
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.
806 truss_lwpid
= my_realloc(truss_lwpid
, sizeof (lwpid_t
), NULL
);
809 (void) Plwp_iter(Proc
, create_thread
, &count
);
812 (void) printf("(Warning: no matching active LWPs found, "
818 * Set all of the truss worker threads running now.
820 (void) mutex_lock(&truss_lock
);
821 for (i
= 0; i
< truss_maxlwp
; 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)
833 (void) Punsetflags(Proc
, PR_ASYNC
);
837 flags
= PRELEASE_CLEAR
;
839 flags
|= PRELEASE_HANG
;
840 Prelease(Proc
, flags
);
843 retc
= (leave_hung
? 0 : wait4all());
846 interrupt
= 0; /* another interrupt kills the report */
850 report(pri
, times(&tms
) - starttime
);
852 } else if (cflag
&& fflag
) {
856 exit(retc
); /* exit with exit status of created process, else 0 */
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();
870 int leave_it_hung
= FALSE
;
871 int reset_traps
= FALSE
;
874 int ow_in_effect
= 0;
877 char *ow_string
= NULL
;
879 sysset_t running_set
;
880 int dotrace
= lwptrace(Psp
->pr_pid
, Lsp
->pr_lwpid
);
884 pri
->syslast
= Lsp
->pr_stime
;
885 pri
->usrlast
= Lsp
->pr_utime
;
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).
898 if (interrupt
| sigusr1
) {
899 (void) Lstop(Lwp
, MILLISEC
);
900 if (Lstate(Lwp
) == PS_RUN
)
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
))
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
);
928 req_flag
= requested(pri
, req_flag
,
930 (void) mutex_unlock(&truss_lock
);
934 data_model
= Psp
->pr_dmodel
;
935 if (Lstate(Lwp
) == PS_UNDEAD
)
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".
963 Lgrab(Proc
, who
, &gcode
);
965 abend("Lgrab error: ",
967 pri
->lwpstat
= Lsp
= Lstatus(Lwp
);
968 (void) mutex_unlock(&truss_lock
);
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
);
977 (void) fputs(pri
->exec_string
, stdout
);
978 (void) fputc('\n', stdout
);
979 } else if (pri
->length
) {
980 (void) fputc('\n', stdout
);
984 "%s\t*** cannot trace across exec() of %s ***\n",
985 pri
->pname
, pri
->sys_path
);
988 "%s\t*** lost control of process ***\n",
992 (void) mutex_unlock(&truss_lock
);
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");
1003 (void) mutex_lock(&truss_lock
);
1005 what
= Lsp
->pr_what
;
1008 switch (Lsp
->pr_why
) {
1012 req_flag
= signalled(pri
, req_flag
, dotrace
);
1013 if (Sflag
&& !first
&& prismember(&sighang
, what
))
1014 leave_it_hung
= TRUE
;
1017 if (what
== FLTBPT
) {
1020 (void) Pstop(Proc
, 0);
1021 rval
= function_trace(pri
, first
, 0, dotrace
);
1023 leave_it_hung
= TRUE
;
1027 if (faulted(pri
, dotrace
) &&
1028 Mflag
&& !first
&& prismember(&flthang
, what
))
1029 leave_it_hung
= TRUE
;
1031 case PR_JOBCONTROL
: /* can't happen except first time */
1032 req_flag
= jobcontrol(pri
, dotrace
);
1035 /* protect ourself from operating system error */
1036 if (what
<= 0 || what
> PRMAXSYS
)
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
) {
1059 (void) mutex_lock(&count_lock
);
1060 scp
= Cp
->syscount
[ow_syscall
];
1061 if (ow_subcode
!= -1)
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
);
1074 (void) printf("%s\n", ow_string
);
1077 pri
->syslast
= Lsp
->pr_stime
;
1080 Psetsysentry(Proc
, &running_set
);
1084 * Special cases. Most syscalls are traced on exit.
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
)) {
1094 ow_subcode
= getsubcode(pri
);
1095 pri
->syslast
= Lsp
->pr_stime
;
1097 (Pstatus(Proc
))->pr_sysentry
;
1098 Psetsysentry(Proc
, &full_set
);
1099 } else if (dotrace
&& Eflag
&&
1100 prismember(&trace
, what
)) {
1101 (void) sysentry(pri
, dotrace
);
1103 ow_string
= my_malloc(
1104 strlen(pri
->sys_string
) + 1, NULL
);
1105 (void) strcpy(ow_string
,
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
);
1117 printf("%s\n", pri
->sys_string
);
1121 *pri
->sys_string
= '\0';
1123 if (what
== SYS_exit
)
1127 show_cred(pri
, FALSE
, TRUE
);
1128 (void) sysentry(pri
, dotrace
);
1129 if (dotrace
&& !cflag
&&
1130 prismember(&trace
, what
)) {
1132 my_realloc(pri
->exec_string
,
1133 strlen(pri
->sys_string
) + 1,
1135 (void) strcpy(pri
->exec_pname
,
1137 (void) strcpy(pri
->exec_string
,
1139 pri
->length
+= strlen(pri
->sys_string
);
1140 pri
->exec_lwpid
= Lsp
->pr_lwpid
;
1143 *pri
->sys_string
= '\0';
1146 if (dotrace
&& (cflag
|| Eflag
) &&
1147 prismember(&trace
, what
)) {
1148 pri
->syslast
= Lsp
->pr_stime
;
1152 if (dotrace
&& Tflag
&& !first
&&
1153 (prismember(&syshang
, what
) ||
1154 (exit_called
&& prismember(&syshang
, SYS_exit
))))
1155 leave_it_hung
= TRUE
;
1158 /* check for write open of a /proc file */
1159 if (what
== SYS_openat
|| what
== SYS_openat64
||
1160 what
== SYS_open
|| what
== SYS_open64
) {
1163 (void) sysentry(pri
, dotrace
);
1164 pri
->Errno
= Lsp
->pr_errno
;
1165 pri
->ErrPriv
= Lsp
->pr_errpriv
;
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
)) {
1189 (void) printf("%s\n",
1194 (void) mutex_unlock(
1200 * Process opened someone else.
1201 * The open is being reissued.
1202 * Don't report this one.
1205 *pri
->sys_string
= '\0';
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
1219 (void) Pstopstatus(Proc
, PCNULL
, 0);
1220 data_model
= Psp
->pr_dmodel
;
1222 if (sysexit(pri
, dotrace
))
1224 if (what
== SYS_lwp_create
&& pri
->Rval1
!= 0) {
1225 struct ps_lwphandle
*new_Lwp
;
1228 if ((new_Lwp
= grab_lwp(pri
->Rval1
)) != NULL
) {
1229 (void) thr_sigsetmask(SIG_SETMASK
,
1231 if (thr_create(NULL
, 0, worker_thread
,
1232 new_Lwp
, THR_BOUND
| THR_SUSPENDED
,
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
,
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
,
1264 who
= Lsp
->pr_lwpid
;
1267 Lgrab(Proc
, who
, &gcode
);
1269 abend("Lgrab error: ",
1270 Lgrab_error(gcode
));
1271 pri
->lwpstat
= Lsp
= Lstatus(Lwp
);
1277 (void) fprintf(stderr
,
1278 "unknown reason for stopping: %d/%d\n",
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
);
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
);
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
)
1317 is_vfork_child
= FALSE
;
1322 if (leave_it_hung
) {
1323 (void) mutex_unlock(&truss_lock
);
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
1340 reset_traps
= FALSE
;
1341 (void) Lsetrun(Lwp
, 0, PRSTEP
);
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
);
1351 (void) printf("%s\t*** Expected PR_FAULTED/"
1352 "FLTTRACE stop following vfork()\n",
1357 if (Lstate(Lwp
) == PS_STOP
) {
1360 if (interrupt
| sigusr1
) {
1361 (void) mutex_unlock(&truss_lock
);
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.
1370 if (Lsp
->pr_why
== PR_REQUESTED
) {
1371 (void) mutex_unlock(&truss_lock
);
1376 if (Lsetrun(Lwp
, 0, flags
) != 0 &&
1377 Lstate(Lwp
) != PS_LOST
&&
1378 Lstate(Lwp
) != PS_UNDEAD
) {
1379 (void) mutex_unlock(&truss_lock
);
1381 abend("cannot start subject lwp", NULL
);
1387 (void) mutex_unlock(&truss_lock
);
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
);
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
) {
1407 (void) mutex_lock(&count_lock
);
1408 scp
= Cp
->syscount
[ow_syscall
];
1409 if (ow_subcode
!= -1)
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
);
1422 (void) printf("%s\n", ow_string
);
1425 pri
->syslast
= Lsp
->pr_stime
;
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();
1440 for (i
= 0; i
< truss_maxlwp
; i
++) {
1441 if (truss_lwpid
[i
] == my_id
) {
1446 if (--truss_nlwp
!= 0) {
1447 (void) cond_broadcast(&truss_cv
);
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();
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;
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
);
1517 (void) cond_broadcast(&truss_cv
);
1520 if (!leave_hung
&& Lstate(Lwp
) == PS_STOP
)
1521 (void) Lsetrun(Lwp
, 0, 0);
1525 (void) mutex_unlock(&truss_lock
);
1530 * Give a base date for time stamps, adjusted to the
1531 * stop time of the selected (first or created) process.
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
;
1545 hrtime_t delta
= basehrtime
-
1546 ((hrtime_t
)Cp
->basetime
.tv_sec
* NANOSEC
+
1547 Cp
->basetime
.tv_nsec
);
1550 basedate
->tv_sec
-= (time_t)(delta
/ NANOSEC
);
1551 basedate
->tv_usec
-= (delta
% NANOSEC
) / 1000;
1552 if (basedate
->tv_usec
< 0) {
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
)
1563 "Base time stamp: %ld.%4.4ld [ %.20s%s %.4s ]\n",
1564 basedate
->tv_sec
, basedate
->tv_usec
/ 100,
1565 ptime
, pdst
, ptime
+ 20);
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
1582 struct timeval basedate
;
1583 hrtime_t basehrtime
;
1584 struct syscount
*scp
;
1586 timestruc_t c_basetime
;
1588 /* Make sure we only configure the basetime for the first truss proc */
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.
1635 unsigned char *buf
= NULL
;
1640 /* ensure that we are in fact a child process */
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
;
1658 if (i
+ sizeof (fentry
) > bufsz
) {
1659 buf
= my_realloc(buf
, i
+ j
+ sizeof (fentry
),
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
),
1667 if (write(sfd
, buf
, sizeof (fentry
) + i
+ j
) == -1)
1668 abend("Error writing to tmp file", NULL
);
1669 ntry
= iter_next(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
);
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.
1706 size_t c_offset
= 0;
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
) !=
1723 abend("Unable to perform full read of hdntry", NULL
);
1724 c_offset
+= sizeof (hdntry_t
);
1726 switch (ntry
.type
) {
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",
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",
1753 c_offset
+= ntry
.sz_key
;
1755 add_fcall(fcall_tbl
, t
, s
, ntry
.count
);
1761 size_t bfsz
= sizeof (struct counts
) + maxsyscalls()
1762 * sizeof (struct syscount
);
1764 struct syscount
*sscp
;
1766 if (ntry
.sz_key
!= bfsz
)
1767 abend("cts/syscts size does not sanity check",
1769 ncp
= my_malloc(ntry
.sz_key
, NULL
);
1771 if (pread(sfd
, ncp
, ntry
.sz_key
, c_offset
) !=
1773 abend("Unable to perform full read of cts",
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
);
1806 for (subcode
= 0; subcode
< n
; subcode
++,
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
);
1825 abend("Unknown file entry type encountered", NULL
);
1830 if (fstat(sfd
, &fsi
) == -1)
1831 abend("Error stat-ing tempfile", NULL
);
1832 filesz
= fsi
.st_size
;
1839 make_pname(private_t
*pri
, id_t tid
)
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
;
1855 s
+= sprintf(s
, "%d", (int)pid
);
1857 s
+= sprintf(s
, "/%d", (int)lwpid
);
1859 s
+= sprintf(s
, "@%d", (int)tid
);
1861 *s
++ = ':', *s
++ = '\t';
1862 if (ff
&& lf
&& s
< pri
->pname
+ 9)
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.
1878 putpname(private_t
*pri
)
1881 (void) fputs(pri
->pname
, stdout
);
1885 * Print the timestamp, if requested (-d, -D, or -E).
1888 timestamp(private_t
*pri
)
1890 const lwpstatus_t
*Lsp
= pri
->lwpstat
;
1894 if (!(dflag
|Dflag
|Eflag
) || !(Lsp
->pr_flags
& PR_STOPPED
))
1897 seconds
= Lsp
->pr_tstamp
.tv_sec
- Cp
->basetime
.tv_sec
;
1898 fraction
= Lsp
->pr_tstamp
.tv_nsec
- Cp
->basetime
.tv_nsec
;
1901 fraction
+= NANOSEC
;
1903 /* fraction in 1/10 milliseconds, rounded up */
1904 fraction
= (fraction
+ 50000) / 100000;
1905 if (fraction
>= (MILLISEC
* 10)) {
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
;
1923 fraction
+= (MILLISEC
* 10);
1925 (void) printf("%2d.%4.4d\t", seconds
, fraction
);
1929 seconds
= Lsp
->pr_stime
.tv_sec
- pri
->syslast
.tv_sec
;
1930 fraction
= Lsp
->pr_stime
.tv_nsec
- pri
->syslast
.tv_nsec
;
1934 fraction
+= NANOSEC
;
1936 /* fraction in 1/10 milliseconds, rounded up */
1937 fraction
= (fraction
+ 50000) / 100000;
1938 if (fraction
>= (MILLISEC
* 10)) {
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.
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 */
1965 /* generate path for directory containing file */
1966 if ((p
= strrchr(path
, '/')) == NULL
) { /* no '/' */
1968 *p
++ = '.'; /* current directory */
1970 } else if (p
== path
) { /* leading '/' */
1972 *p
++ = '/'; /* root directory */
1974 } else { /* embedded '/' */
1975 dir
= path
; /* directory path */
1979 if (access(dir
, W_OK
|X_OK
) != 0) {
1980 /* not writeable/searchable */
1983 } else { /* create file and set ownership correctly */
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 */
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);
2004 * Mark it close-on-exec so created processes don't inherit it.
2007 (void) fcntl(fd
, F_SETFD
, FD_CLOEXEC
);
2017 (void) fcntl(2, F_DUPFD
, 1);
2018 } else if (ofd
!= 1) {
2020 (void) fcntl(ofd
, F_DUPFD
, 1);
2022 /* if no stderr, make it the same file */
2023 if ((ofd
= dup(2)) < 0)
2024 (void) fcntl(1, F_DUPFD
, 2);
2031 * Accumulate time differencies: a += e - s;
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
;
2041 } else if (ap
->tv_nsec
< 0) {
2042 ap
->tv_nsec
+= NANOSEC
;
2048 lib_sort(const void *p1
, const void *p2
)
2054 hentry_t
*t1
= (hentry_t
*)p1
;
2055 hentry_t
*t2
= (hentry_t
*)p2
;
2060 if ((cmpr
= strcmp(p
, q
)) == 0) {
2070 return (strcmp(p
, q
));
2077 report(private_t
*pri
, time_t lapse
) /* elapsed time, clock ticks */
2085 timestruc_t tickzero
;
2087 timestruc_t ticktot
;
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 *)""),
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 *)""),
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
);
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
);
2140 qsort((void *)stbl
, elem
, sizeof (hentry_t
),
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
);
2155 "\nsyscall seconds calls errors\n");
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
);
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
));
2171 accumulate(&ticktot
, &ticks
, &tickzero
);
2174 (void) printf(" %7ld", count
);
2175 if ((error
= scp
->error
) != 0)
2176 (void) printf(" %7ld", error
);
2177 (void) fputc('\n', stdout
);
2186 " -------- ------ ----\n");
2187 (void) printf("sys totals: ");
2189 (void) printf(" %7ld %6ld\n", total
, errtot
);
2193 (void) printf("usr time: ");
2194 prtim(&Cp
->usrtotal
);
2195 (void) fputc('\n', stdout
);
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: ");
2205 (void) fputc('\n', stdout
);
2210 prtim(timestruc_t
*tp
)
2214 if ((sec
= tp
->tv_sec
) != 0) /* whole seconds */
2215 (void) printf("%5lu", sec
);
2219 (void) printf(".%3.3ld", tp
->tv_nsec
/1000000); /* fraction */
2223 * Gather process id's.
2224 * Return 0 on success, != 0 on failure.
2227 pids(char *arg
, proc_set_t
*grab
)
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
));
2239 for (i
= 0; i
< ngrab
; i
++)
2240 if (grab
[i
].pid
== pid
) /* duplicate */
2244 grab
[ngrab
].pid
= pid
;
2245 grab
[ngrab
].lwps
= lwps
;
2248 (void) fprintf(stderr
, "%s: duplicate process-id ignored: %d\n",
2254 * Report psargs string.
2257 psargs(private_t
*pri
)
2259 pid_t pid
= Pstatus(Proc
)->pr_pid
;
2262 if (proc_get_psinfo(pid
, &psinfo
) == 0)
2263 (void) printf("%spsargs: %.64s\n",
2264 pri
->pname
, psinfo
.pr_psargs
);
2267 (void) printf("%s\t*** Cannot read psinfo file for pid %d\n",
2268 pri
->pname
, (int)pid
);
2273 fetchstring(private_t
*pri
, long addr
, int maxleng
)
2280 if (pri
->str_bsize
== 0) /* initial allocation of string 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
);
2289 (nbyte
= strlen(string
)) > 0) {
2290 while (leng
+ nbyte
>= pri
->str_bsize
)
2292 my_realloc(pri
->str_buffer
,
2293 pri
->str_bsize
*= 2, "string buffer");
2294 (void) strcpy(pri
->str_buffer
+leng
, string
);
2301 pri
->str_buffer
[leng
] = '\0';
2303 return (pri
->str_buffer
);
2307 getset(prpriv_t
*p
, priv_ptype_t set
)
2309 return ((priv_set_t
*)
2310 &p
->pr_sets
[priv_getsetbyname(set
) * p
->pr_setsize
]);
2314 show_cred(private_t
*pri
, int new, int loadonly
)
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
);
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
);
2330 if (!loadonly
&& !cflag
&& prismember(&trace
, SYS_execve
)) {
2333 if ((new && cred
.pr_ruid
!= cred
.pr_suid
) ||
2334 cred
.pr_ruid
!= credentials
.pr_ruid
||
2335 cred
.pr_suid
!= credentials
.pr_suid
)
2337 "%s *** SUID: ruid/euid/suid = %d / %d / %d ***\n",
2342 if ((new && cred
.pr_rgid
!= cred
.pr_sgid
) ||
2343 cred
.pr_rgid
!= credentials
.pr_rgid
||
2344 cred
.pr_sgid
!= credentials
.pr_sgid
)
2346 "%s *** SGID: rgid/egid/sgid = %d / %d / %d ***\n",
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
);
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",
2363 strlen(s
) > strlen(t
) ? t
: s
);
2370 proc_free_priv(privdata
);
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
;
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
);
2397 (void) cond_broadcast(&gps
->fork_cv
);
2398 (void) mutex_unlock(&gps
->fork_lock
);
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
);
2411 (void) cond_broadcast(&gps
->fork_cv
);
2412 (void) mutex_unlock(&gps
->fork_lock
);
2416 childpid
= getpid();
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
);
2442 * Add ourself to the set of truss processes
2443 * and notify the parent to carry on.
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
);
2461 data_model
= Psp
->pr_dmodel
;
2465 pri
->syslast
= Psp
->pr_stime
;
2466 pri
->usrlast
= Psp
->pr_utime
;
2468 flags
= PR_FORK
| PR_ASYNC
;
2470 flags
|= PR_BPTADJ
; /* needed for x86 */
2471 (void) Psetflags(Proc
, flags
);
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
;
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
;
2495 Psp
= Pstatus(Proc
);
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
);
2508 (void) Punsetflags(Proc
, PR_FORK
);
2509 procadd(set
->pid
, set
->lwps
);
2510 show_cred(pri
, TRUE
, FALSE
);
2515 * Release process from control.
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.
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()");
2537 "%s\t*** Cannot release child process, pid# %d\n",
2538 pri
->pname
, (int)pid
);
2541 if (fd
>= 0) /* run-on-last-close sets the process running */
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
) {
2557 } else if (sig
== SIGUSR2
) {
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);
2572 errmsg(const char *s
, const char *q
)
2579 (void) strcpy(msg
, command
);
2580 (void) strcat(msg
, ": ");
2583 (void) strcat(msg
, s
);
2585 (void) strcat(msg
, q
);
2586 (void) strcat(msg
, "\n");
2587 (void) write(2, msg
, (size_t)strlen(msg
));
2592 abend(const char *s
, const char *q
)
2594 (void) thr_sigsetmask(SIG_SETMASK
, &fillset
, NULL
);
2598 clear_breakpoints();
2599 (void) Punsetflags(Proc
, PR_ASYNC
);
2600 Prelease(Proc
, created
? PRELEASE_KILL
: PRELEASE_CLEAR
);
2611 * If allocation fails then print a message and abort.
2614 my_realloc(void *buf
, size_t size
, const char *msg
)
2616 if ((buf
= realloc(buf
, size
)) == NULL
) {
2618 abend("cannot allocate ", msg
);
2620 abend("memory allocation failure", NULL
);
2627 my_calloc(size_t nelem
, size_t elsize
, const char *msg
)
2631 if ((buf
= calloc(nelem
, elsize
)) == NULL
) {
2633 abend("cannot allocate ", msg
);
2635 abend("memory allocation failure", NULL
);
2642 my_malloc(size_t size
, const char *msg
)
2644 return (my_realloc(NULL
, size
, msg
));
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
);
2662 rc
|= 0x80; /* +128 to indicate sig */
2665 if (errno
!= EINTR
&& errno
!= ERESTART
)
2669 if (i
>= 10) /* repeated interrupts */
2676 letgo(private_t
*pri
)
2678 (void) printf("%s\t*** process otherwise traced, releasing ...\n",
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 */
2701 * OR the second set into the first.
2702 * The sets must be the same size.
2705 or_set(uint32_t *sp1
, const uint32_t *sp2
, size_t n
)