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
;
136 free(pri
->sys_string
);
137 if (pri
->exec_string
)
138 free(pri
->exec_string
);
140 free(pri
->str_buffer
);
145 * This is called by the main thread (via create_thread())
146 * and is also called from other threads in worker_thread()
147 * while holding truss_lock. No further locking is required.
150 insert_lwpid(lwpid_t lwpid
)
155 for (i
= 0; i
< truss_maxlwp
; i
++) {
156 if (truss_lwpid
[i
] == 0)
159 if (i
== truss_maxlwp
) {
160 /* double the size of the array */
161 truss_lwpid
= my_realloc(truss_lwpid
,
162 truss_maxlwp
* 2 * sizeof (lwpid_t
), NULL
);
163 (void) memset(&truss_lwpid
[truss_maxlwp
], 0,
164 truss_maxlwp
* sizeof (lwpid_t
));
167 truss_lwpid
[i
] = lwpid
;
171 * This is called from the first worker thread to encounter one of
172 * (leave_hung || interrupt || sigusr1). It must notify all other
173 * worker threads of the same condition. truss_lock is held.
176 broadcast_signals(void)
178 static int int_notified
= FALSE
;
179 static int usr1_notified
= FALSE
;
180 static int usr2_notified
= FALSE
;
181 lwpid_t my_id
= thr_self();
185 if (interrupt
&& !int_notified
) {
187 for (i
= 0; i
< truss_maxlwp
; i
++) {
188 if ((lwpid
= truss_lwpid
[i
]) != 0 && lwpid
!= my_id
)
189 (void) thr_kill(lwpid
, interrupt
);
192 if (sigusr1
&& !usr1_notified
) {
193 usr1_notified
= TRUE
;
194 for (i
= 0; i
< truss_maxlwp
; i
++) {
195 if ((lwpid
= truss_lwpid
[i
]) != 0 && lwpid
!= my_id
)
196 (void) thr_kill(lwpid
, SIGUSR1
);
199 if (leave_hung
&& !usr2_notified
) {
200 usr2_notified
= TRUE
;
201 for (i
= 0; i
< truss_maxlwp
; i
++) {
202 if ((lwpid
= truss_lwpid
[i
]) != 0 && lwpid
!= my_id
)
203 (void) thr_kill(lwpid
, SIGUSR2
);
208 static struct ps_lwphandle
*
209 grab_lwp(lwpid_t who
)
211 struct ps_lwphandle
*Lwp
;
214 if ((Lwp
= Lgrab(Proc
, who
, &gcode
)) == NULL
) {
215 if (gcode
!= G_NOPROC
) {
216 (void) fprintf(stderr
,
217 "%s: cannot grab LWP %u in process %d,"
219 command
, who
, (int)Pstatus(Proc
)->pr_pid
,
221 interrupt
= SIGTERM
; /* post an interrupt */
228 * Iteration function called for each initial lwp in the controlled process.
232 create_thread(void *arg
, const lwpstatus_t
*Lsp
)
234 struct ps_lwphandle
*new_Lwp
;
238 if (lwptrace(Pstatus(Proc
)->pr_pid
, Lsp
->pr_lwpid
))
241 if ((new_Lwp
= grab_lwp(Lsp
->pr_lwpid
)) != NULL
) {
242 if (thr_create(NULL
, 0, worker_thread
, new_Lwp
,
243 THR_BOUND
| THR_SUSPENDED
, &lwpid
) != 0)
244 abend("cannot create lwp to follow child lwp", NULL
);
251 main(int argc
, char *argv
[])
262 proc_set_t
*grab
= NULL
;
263 const pstatus_t
*Psp
;
264 const lwpstatus_t
*Lsp
;
267 /* a few of these need to be initialized to NULL */
272 * Make sure fd's 0, 1, and 2 are allocated,
273 * just in case truss was invoked from init.
275 while ((i
= open("/dev/null", O_RDWR
)) >= 0 && i
< 2)
280 starttime
= times(&tms
); /* for elapsed timing */
282 /* this should be per-traced-process */
283 pagesize
= sysconf(_SC_PAGESIZE
);
285 /* command name (e.g., "truss") */
286 if ((command
= strrchr(argv
[0], '/')) != NULL
)
291 /* set up the initial private data */
292 (void) mutex_init(&truss_lock
, USYNC_THREAD
, NULL
);
293 (void) mutex_init(&count_lock
, USYNC_THREAD
, NULL
);
294 (void) cond_init(&truss_cv
, USYNC_THREAD
, NULL
);
295 if (thr_keycreate(&private_key
, free_private
) == ENOMEM
)
296 abend("memory allocation failure", NULL
);
305 prfillset(&trace
); /* default: trace all system calls */
306 premptyset(&verbose
); /* default: no syscall verbosity */
307 premptyset(&rawout
); /* default: no raw syscall interpretation */
309 prfillset(&signals
); /* default: trace all signals */
311 prfillset(&faults
); /* default: trace all faults */
312 prdelset(&faults
, FLTPAGE
); /* except this one */
314 premptyset(&readfd
); /* default: dump no buffers */
315 premptyset(&writefd
);
317 premptyset(&syshang
); /* default: hang on no system calls */
318 premptyset(&sighang
); /* default: hang on no signals */
319 premptyset(&flthang
); /* default: hang on no faults */
321 (void) sigemptyset(&emptyset
); /* for unblocking all signals */
322 (void) sigfillset(&fillset
); /* for blocking all signals */
324 #define OPTIONS "FpfcaeildDEht:T:v:x:s:S:m:M:u:U:r:w:o:"
325 while ((opt
= getopt(argc
, argv
, OPTIONS
)) != EOF
) {
327 case 'F': /* force grabbing (no O_EXCL) */
330 case 'p': /* grab processes */
333 case 'f': /* follow children */
336 case 'c': /* don't trace, just count */
338 iflag
= TRUE
; /* implies no interruptable syscalls */
340 case 'a': /* display argument lists */
343 case 'e': /* display environments */
346 case 'i': /* don't show interruptable syscalls */
349 case 'l': /* show lwp id for each syscall */
352 case 'h': /* debugging: report hash stats */
355 case 'd': /* show time stamps */
358 case 'D': /* show time deltas */
362 Eflag
= TRUE
; /* show syscall times */
364 case 't': /* system calls to trace */
365 if (syslist(optarg
, &trace
, &tflag
))
368 case 'T': /* system calls to hang process */
369 if (syslist(optarg
, &syshang
, &Tflag
))
372 case 'v': /* verbose interpretation of syscalls */
373 if (syslist(optarg
, &verbose
, &vflag
))
376 case 'x': /* raw interpretation of syscalls */
377 if (syslist(optarg
, &rawout
, &xflag
))
380 case 's': /* signals to trace */
381 if (siglist(pri
, optarg
, &signals
, &sflag
))
384 case 'S': /* signals to hang process */
385 if (siglist(pri
, optarg
, &sighang
, &Sflag
))
388 case 'm': /* machine faults to trace */
389 if (fltlist(optarg
, &faults
, &mflag
))
392 case 'M': /* machine faults to hang process */
393 if (fltlist(optarg
, &flthang
, &Mflag
))
396 case 'u': /* user library functions to trace */
397 if (liblist(optarg
, 0))
400 case 'U': /* user library functions to hang */
401 if (liblist(optarg
, 1))
404 case 'r': /* show contents of read(fd) */
405 if (fdlist(optarg
, &readfd
))
408 case 'w': /* show contents of write(fd) */
409 if (fdlist(optarg
, &writefd
))
412 case 'o': /* output file for trace */
416 if ((ofd
= xcreat(optarg
)) < 0) {
430 /* if -a or -e was specified, force tracing of exec() */
432 praddset(&trace
, SYS_execve
);
435 * Make sure that all system calls, signals, and machine faults
436 * that hang the process are added to their trace sets.
438 prorset(&trace
, &syshang
);
439 prorset(&signals
, &sighang
);
440 prorset(&faults
, &flthang
);
445 /* collect the specified process ids */
446 if (pflag
&& argc
> 0) {
447 grab
= my_malloc(argc
* sizeof (proc_set_t
),
448 "memory for process-ids");
453 if (errflg
|| (argc
<= 0 && ngrab
<= 0)) {
454 (void) fprintf(stderr
,
455 "usage:\t%s [-fcaeildDEF] [-[tTvx] [!]syscalls] [-[sS] [!]signals]\\\n",
457 (void) fprintf(stderr
,
458 "\t[-[mM] [!]faults] [-[rw] [!]fds] [-[uU] [!]libs:[:][!]funcs]\\\n");
459 (void) fprintf(stderr
,
460 "\t[-o outfile] command | -p pid[/lwps] ...\n");
464 if (argc
> 0) { /* create the controlled process */
468 Proc
= Pcreate(argv
[0], &argv
[0], &err
, path
, sizeof (path
));
472 (void) fprintf(stderr
,
473 "%s: cannot trace set-id or "
474 "unreadable object file: %s\n",
478 (void) fprintf(stderr
,
479 "%s: cannot control _LP64 "
484 (void) fprintf(stderr
,
485 "%s: cannot execute program: %s\n",
489 (void) fprintf(stderr
,
490 "%s: cannot find program: %s\n",
496 (void) fprintf(stderr
, "%s: %s\n",
497 command
, Pcreate_error(err
));
502 if (fflag
|| Dynpat
!= NULL
)
503 (void) Psetflags(Proc
, PR_FORK
);
505 (void) Punsetflags(Proc
, PR_FORK
);
509 data_model
= Psp
->pr_dmodel
;
510 created
= Psp
->pr_pid
;
512 (void) sysentry(pri
, 1);
514 if (!cflag
&& prismember(&trace
, SYS_execve
)) {
515 pri
->exec_string
= my_realloc(pri
->exec_string
,
516 strlen(pri
->sys_string
) + 1, NULL
);
517 (void) strcpy(pri
->exec_pname
, pri
->pname
);
518 (void) strcpy(pri
->exec_string
, pri
->sys_string
);
519 pri
->length
+= strlen(pri
->sys_string
);
520 pri
->exec_lwpid
= pri
->lwpstat
->pr_lwpid
;
522 *pri
->sys_string
= '\0';
524 pri
->syslast
= Psp
->pr_stime
;
525 pri
->usrlast
= Psp
->pr_utime
;
529 * Now that we have created the victim process,
530 * give ourself a million file descriptors.
531 * This is enough to deal with a multithreaded
532 * victim process that has half a million lwps.
534 rlim
.rlim_cur
= 1024 * 1024;
535 rlim
.rlim_max
= 1024 * 1024;
536 if ((Euid
!= 0 || setrlimit(RLIMIT_NOFILE
, &rlim
) != 0) &&
537 getrlimit(RLIMIT_NOFILE
, &rlim
) == 0) {
539 * Failing the million, give ourself as many
540 * file descriptors as we can get.
542 rlim
.rlim_cur
= rlim
.rlim_max
;
543 (void) setrlimit(RLIMIT_NOFILE
, &rlim
);
545 (void) enable_extended_FILE_stdio(-1, -1);
547 setoutput(ofd
); /* establish truss output */
550 if (setvbuf(stdout
, (char *)NULL
, _IOFBF
, MYBUFSIZ
) != 0)
551 abend("setvbuf() failure", NULL
);
554 * Set up signal dispositions.
556 if (created
&& (oflag
|| !istty
)) { /* ignore interrupts */
557 (void) sigset(SIGHUP
, SIG_IGN
);
558 (void) sigset(SIGINT
, SIG_IGN
);
559 (void) sigset(SIGQUIT
, SIG_IGN
);
560 } else { /* receive interrupts */
561 if (sigset(SIGHUP
, SIG_IGN
) == SIG_DFL
)
562 (void) sigset(SIGHUP
, intr
);
563 if (sigset(SIGINT
, SIG_IGN
) == SIG_DFL
)
564 (void) sigset(SIGINT
, intr
);
565 if (sigset(SIGQUIT
, SIG_IGN
) == SIG_DFL
)
566 (void) sigset(SIGQUIT
, intr
);
568 (void) sigset(SIGTERM
, intr
);
569 (void) sigset(SIGUSR1
, intr
);
570 (void) sigset(SIGUSR2
, intr
);
571 (void) sigset(SIGPIPE
, intr
);
573 /* don't accumulate zombie children */
574 (void) sigset(SIGCLD
, SIG_IGN
);
576 /* create shared mem space for global mutexes */
578 sharedmem
= (fflag
|| Dynpat
!= NULL
|| ngrab
> 1);
579 gps
= (void *)mmap(NULL
, sizeof (struct global_psinfo
),
580 PROT_READ
|PROT_WRITE
,
581 MAP_ANON
| (sharedmem
? MAP_SHARED
: MAP_PRIVATE
),
583 if (gps
== MAP_FAILED
)
584 abend("cannot allocate ", "memory for counts");
585 i
= sharedmem
? USYNC_PROCESS
: USYNC_THREAD
;
586 (void) mutex_init(&gps
->ps_mutex0
, i
, NULL
);
587 (void) mutex_init(&gps
->ps_mutex1
, i
, NULL
);
588 (void) mutex_init(&gps
->fork_lock
, i
, NULL
);
589 (void) cond_init(&gps
->fork_cv
, i
, NULL
);
592 /* config tmp file if counting and following */
593 if (fflag
&& cflag
) {
594 char *tmps
= tempnam("/var/tmp", "truss");
595 sfd
= open(tmps
, O_CREAT
|O_APPEND
|O_EXCL
|O_RDWR
, 0600);
597 abend("Error creating tmpfile", NULL
);
598 if (unlink(tmps
) == -1)
599 abend("Error unlinking tmpfile", NULL
);
606 procadd(created
, NULL
);
607 show_cred(pri
, TRUE
, FALSE
);
608 } else { /* grab the specified processes */
612 while (i
< ngrab
) { /* grab first process */
613 if (grabit(pri
, &grab
[i
++])) {
623 while (i
< ngrab
) { /* grab the remainder */
624 proc_set_t
*set
= &grab
[i
++];
626 (void) mutex_lock(&truss_lock
);
629 (void) fprintf(stderr
,
630 "%s: cannot fork to control process, pid# %d\n",
631 command
, (int)set
->pid
);
634 (void) mutex_unlock(&truss_lock
);
635 continue; /* parent carries on */
637 case 0: /* child grabs process */
638 (void) mutex_unlock(&truss_lock
);
641 if (grabit(pri
, set
)) {
656 * If running setuid-root, become root for real to avoid
657 * affecting the per-user limitation on the maximum number
658 * of processes (one benefit of running setuid-root).
665 if (!created
&& aflag
&& prismember(&trace
, SYS_execve
)) {
670 if (created
&& Pstate(Proc
) != PS_STOP
) /* assertion */
671 if (!(interrupt
| sigusr1
))
672 abend("ASSERT error: process is not stopped", NULL
);
674 traceeven
= trace
; /* trace these system calls */
676 /* trace these regardless, even if we don't report results */
677 praddset(&traceeven
, SYS_exit
);
678 praddset(&traceeven
, SYS_lwp_create
);
679 praddset(&traceeven
, SYS_lwp_exit
);
680 praddset(&traceeven
, SYS_execve
);
681 praddset(&traceeven
, SYS_openat
);
682 praddset(&traceeven
, SYS_openat64
);
683 praddset(&traceeven
, SYS_open
);
684 praddset(&traceeven
, SYS_open64
);
685 praddset(&traceeven
, SYS_vfork
);
686 praddset(&traceeven
, SYS_forksys
);
688 /* for I/O buffer dumps, force tracing of read()s and write()s */
689 if (!isemptyset(&readfd
)) {
690 praddset(&traceeven
, SYS_read
);
691 praddset(&traceeven
, SYS_readv
);
692 praddset(&traceeven
, SYS_pread
);
693 praddset(&traceeven
, SYS_pread64
);
694 praddset(&traceeven
, SYS_recv
);
695 praddset(&traceeven
, SYS_recvfrom
);
696 praddset(&traceeven
, SYS_recvmsg
);
698 if (!isemptyset(&writefd
)) {
699 praddset(&traceeven
, SYS_write
);
700 praddset(&traceeven
, SYS_writev
);
701 praddset(&traceeven
, SYS_pwrite
);
702 praddset(&traceeven
, SYS_pwrite64
);
703 praddset(&traceeven
, SYS_send
);
704 praddset(&traceeven
, SYS_sendto
);
705 praddset(&traceeven
, SYS_sendmsg
);
708 if (cflag
|| Eflag
) {
709 Psetsysentry(Proc
, &traceeven
);
711 Psetsysexit(Proc
, &traceeven
);
713 /* special case -- cannot trace sysexit because context is changed */
714 if (prismember(&trace
, SYS_context
)) {
715 (void) Psysentry(Proc
, SYS_context
, TRUE
);
716 (void) Psysexit(Proc
, SYS_context
, FALSE
);
717 prdelset(&traceeven
, SYS_context
);
720 /* special case -- trace exec() on entry to get the args */
721 (void) Psysentry(Proc
, SYS_execve
, TRUE
);
723 /* special case -- sysexit never reached */
724 (void) Psysentry(Proc
, SYS_exit
, TRUE
);
725 (void) Psysentry(Proc
, SYS_lwp_exit
, TRUE
);
726 (void) Psysexit(Proc
, SYS_exit
, FALSE
);
727 (void) Psysexit(Proc
, SYS_lwp_exit
, FALSE
);
729 Psetsignal(Proc
, &signals
); /* trace these signals */
730 Psetfault(Proc
, &faults
); /* trace these faults */
732 /* for function call tracing */
733 if (Dynpat
!= NULL
) {
734 /* trace these regardless, to deal with function calls */
735 (void) Pfault(Proc
, FLTBPT
, TRUE
);
736 (void) Pfault(Proc
, FLTTRACE
, TRUE
);
739 (void) Psetflags(Proc
, PR_BPTADJ
);
742 * Find functions and set breakpoints on grabbed process.
743 * A process stopped on exec() gets its breakpoints set below.
745 if ((Lsp
->pr_why
!= PR_SYSENTRY
&&
746 Lsp
->pr_why
!= PR_SYSEXIT
) ||
747 Lsp
->pr_what
!= SYS_execve
) {
748 establish_breakpoints();
754 * Use asynchronous-stop for multithreaded truss.
755 * truss runs one lwp for each lwp in the target process.
757 (void) Psetflags(Proc
, PR_ASYNC
);
759 /* flush out all tracing flags now. */
763 * If we grabbed a running process, set it running again.
764 * Since we are tracing lwp_create() and lwp_exit(), the
765 * lwps will not change in the process until we create all
766 * of the truss worker threads.
767 * We leave a created process stopped so its exec() can be reported.
769 first
= created
? FALSE
: TRUE
;
771 ((Pstate(Proc
) == PS_STOP
&& Lsp
->pr_why
== PR_REQUESTED
) ||
772 (Lsp
->pr_flags
& PR_DSTOP
)))
780 * Called from main() and from control() after fork().
783 main_thread(int first
)
785 private_t
*pri
= get_private();
793 * Block all signals in the main thread.
794 * Some worker thread will receive signals.
796 (void) thr_sigsetmask(SIG_SETMASK
, &fillset
, NULL
);
799 * If we are dealing with a previously hung process,
800 * arrange not to leave it hung on the same system call.
802 primary_lwp
= (first
&& Pstate(Proc
) == PS_STOP
)?
803 Pstatus(Proc
)->pr_lwp
.pr_lwpid
: 0;
806 * Create worker threads to match the lwps in the target process.
810 truss_lwpid
= my_realloc(truss_lwpid
, sizeof (lwpid_t
), NULL
);
813 (void) Plwp_iter(Proc
, create_thread
, &count
);
816 (void) printf("(Warning: no matching active LWPs found, "
822 * Set all of the truss worker threads running now.
824 (void) mutex_lock(&truss_lock
);
825 for (i
= 0; i
< truss_maxlwp
; i
++) {
827 (void) thr_continue(truss_lwpid
[i
]);
829 (void) mutex_unlock(&truss_lock
);
832 * Wait until all worker threads terminate.
834 while (thr_join(0, NULL
, NULL
) == 0)
837 (void) Punsetflags(Proc
, PR_ASYNC
);
841 flags
= PRELEASE_CLEAR
;
843 flags
|= PRELEASE_HANG
;
844 Prelease(Proc
, flags
);
847 retc
= (leave_hung
? 0 : wait4all());
850 interrupt
= 0; /* another interrupt kills the report */
854 report(pri
, times(&tms
) - starttime
);
856 } else if (cflag
&& fflag
) {
860 exit(retc
); /* exit with exit status of created process, else 0 */
864 worker_thread(void *arg
)
866 struct ps_lwphandle
*Lwp
= (struct ps_lwphandle
*)arg
;
867 const pstatus_t
*Psp
= Pstatus(Proc
);
868 const lwpstatus_t
*Lsp
= Lstatus(Lwp
);
869 struct syscount
*scp
;
870 lwpid_t who
= Lsp
->pr_lwpid
;
871 int first
= (who
== primary_lwp
);
872 private_t
*pri
= get_private();
874 int leave_it_hung
= FALSE
;
875 int reset_traps
= FALSE
;
878 int ow_in_effect
= 0;
881 char *ow_string
= NULL
;
883 sysset_t running_set
;
884 int dotrace
= lwptrace(Psp
->pr_pid
, Lsp
->pr_lwpid
);
888 pri
->syslast
= Lsp
->pr_stime
;
889 pri
->usrlast
= Lsp
->pr_utime
;
892 prfillset(&full_set
);
894 /* we were created with all signals blocked; unblock them */
895 (void) thr_sigsetmask(SIG_SETMASK
, &emptyset
, NULL
);
898 * Run this loop until the victim lwp terminates or we receive
899 * a termination condition (leave_hung | interrupt | sigusr1).
902 if (interrupt
| sigusr1
) {
903 (void) Lstop(Lwp
, MILLISEC
);
904 if (Lstate(Lwp
) == PS_RUN
)
907 if (Lstate(Lwp
) == PS_RUN
) {
908 /* millisecond timeout is for sleeping syscalls */
909 uint_t tout
= (iflag
|| req_flag
)? 0 : MILLISEC
;
912 * If we are to leave this lwp stopped in sympathy
913 * with another lwp that has been left hung, or if
914 * we have been interrupted or instructed to release
915 * our victim process, and this lwp is stopped but
916 * not on an event of interest to /proc, then just
917 * leave it in that state.
919 if ((leave_hung
| interrupt
| sigusr1
) &&
920 (Lsp
->pr_flags
& (PR_STOPPED
|PR_ISTOP
))
924 (void) Lwait(Lwp
, tout
);
925 if (Lstate(Lwp
) == PS_RUN
&&
926 tout
!= 0 && !(interrupt
| sigusr1
)) {
927 (void) mutex_lock(&truss_lock
);
928 if ((Lsp
->pr_flags
& PR_STOPPED
) &&
929 Lsp
->pr_why
== PR_JOBCONTROL
)
930 req_flag
= jobcontrol(pri
, dotrace
);
932 req_flag
= requested(pri
, req_flag
,
934 (void) mutex_unlock(&truss_lock
);
938 data_model
= Psp
->pr_dmodel
;
939 if (Lstate(Lwp
) == PS_UNDEAD
)
941 if (Lstate(Lwp
) == PS_LOST
) { /* we lost control */
943 * After exec(), only one LWP remains in the process.
944 * /proc makes the thread following that LWP receive
945 * EAGAIN (PS_LOST) if the program being exec()ed
946 * is a set-id program. Every other controlling
947 * thread receives ENOENT (because its LWP vanished).
948 * We are the controlling thread for the exec()ing LWP.
949 * We must wait until all of our siblings terminate
950 * before attempting to reopen the process.
952 (void) mutex_lock(&truss_lock
);
953 while (truss_nlwp
> 1)
954 (void) cond_wait(&truss_cv
, &truss_lock
);
955 if (Preopen(Proc
) == 0) { /* we got control back */
957 * We have to free and re-grab the LWP.
958 * The process is guaranteed to be at exit
959 * from exec() or execve() and have only
960 * one LWP, namely this one, and the LWP
961 * is guaranteed to have lwpid == 1.
962 * This "cannot fail".
967 Lgrab(Proc
, who
, &gcode
);
969 abend("Lgrab error: ",
971 pri
->lwpstat
= Lsp
= Lstatus(Lwp
);
972 (void) mutex_unlock(&truss_lock
);
976 /* we really lost it */
977 if (pri
->exec_string
&& *pri
->exec_string
) {
978 if (pri
->exec_pname
[0] != '\0')
979 (void) fputs(pri
->exec_pname
, stdout
);
981 (void) fputs(pri
->exec_string
, stdout
);
982 (void) fputc('\n', stdout
);
983 } else if (pri
->length
) {
984 (void) fputc('\n', stdout
);
988 "%s\t*** cannot trace across exec() of %s ***\n",
989 pri
->pname
, pri
->sys_path
);
992 "%s\t*** lost control of process ***\n",
996 (void) mutex_unlock(&truss_lock
);
999 if (Lstate(Lwp
) != PS_STOP
) {
1000 (void) fprintf(stderr
,
1001 "%s: state = %d\n", command
, Lstate(Lwp
));
1002 abend(pri
->pname
, "uncaught status of subject lwp");
1007 (void) mutex_lock(&truss_lock
);
1009 what
= Lsp
->pr_what
;
1012 switch (Lsp
->pr_why
) {
1016 req_flag
= signalled(pri
, req_flag
, dotrace
);
1017 if (Sflag
&& !first
&& prismember(&sighang
, what
))
1018 leave_it_hung
= TRUE
;
1021 if (what
== FLTBPT
) {
1024 (void) Pstop(Proc
, 0);
1025 rval
= function_trace(pri
, first
, 0, dotrace
);
1027 leave_it_hung
= TRUE
;
1031 if (faulted(pri
, dotrace
) &&
1032 Mflag
&& !first
&& prismember(&flthang
, what
))
1033 leave_it_hung
= TRUE
;
1035 case PR_JOBCONTROL
: /* can't happen except first time */
1036 req_flag
= jobcontrol(pri
, dotrace
);
1039 /* protect ourself from operating system error */
1040 if (what
<= 0 || what
> PRMAXSYS
)
1044 * ow_in_effect checks to see whether or not we
1045 * are attempting to quantify the time spent in
1046 * a one way system call. This is necessary as
1047 * some system calls never return, yet it is desireable
1048 * to determine how much time the traced process
1049 * spends in these calls. To do this, a one way
1050 * flag is set on SYSENTRY when the call is recieved.
1051 * After this, the call mask for the SYSENTRY events
1052 * is filled so that the traced process will stop
1053 * on the entry to the very next system call.
1054 * This appears to the the best way to determine
1055 * system time elapsed between a one way system call.
1056 * Once the next call occurs, values that have been
1057 * stashed are used to record the correct syscall
1058 * and time, and the SYSENTRY event mask is restored
1059 * so that the traced process may continue.
1061 if (dotrace
&& ow_in_effect
) {
1063 (void) mutex_lock(&count_lock
);
1064 scp
= Cp
->syscount
[ow_syscall
];
1065 if (ow_subcode
!= -1)
1068 accumulate(&scp
->stime
,
1069 &Lsp
->pr_stime
, &pri
->syslast
);
1070 accumulate(&Cp
->usrtotal
,
1071 &Lsp
->pr_utime
, &pri
->usrlast
);
1072 pri
->syslast
= Lsp
->pr_stime
;
1073 pri
->usrlast
= Lsp
->pr_utime
;
1074 (void) mutex_unlock(&count_lock
);
1078 (void) printf("%s\n", ow_string
);
1081 pri
->syslast
= Lsp
->pr_stime
;
1084 Psetsysentry(Proc
, &running_set
);
1088 * Special cases. Most syscalls are traced on exit.
1091 case SYS_exit
: /* exit() */
1092 case SYS_lwp_exit
: /* lwp_exit() */
1093 case SYS_context
: /* [get|set]context() */
1094 if (dotrace
&& cflag
&&
1095 prismember(&trace
, what
)) {
1098 ow_subcode
= getsubcode(pri
);
1099 pri
->syslast
= Lsp
->pr_stime
;
1101 (Pstatus(Proc
))->pr_sysentry
;
1102 Psetsysentry(Proc
, &full_set
);
1103 } else if (dotrace
&& Eflag
&&
1104 prismember(&trace
, what
)) {
1105 (void) sysentry(pri
, dotrace
);
1107 ow_string
= my_malloc(
1108 strlen(pri
->sys_string
) + 1, NULL
);
1109 (void) strcpy(ow_string
,
1112 (Pstatus(Proc
))->pr_sysentry
;
1113 Psetsysentry(Proc
, &full_set
);
1114 pri
->syslast
= Lsp
->pr_stime
;
1115 } else if (dotrace
&&
1116 prismember(&trace
, what
)) {
1117 (void) sysentry(pri
, dotrace
);
1121 printf("%s\n", pri
->sys_string
);
1125 *pri
->sys_string
= '\0';
1127 if (what
== SYS_exit
)
1131 show_cred(pri
, FALSE
, TRUE
);
1132 (void) sysentry(pri
, dotrace
);
1133 if (dotrace
&& !cflag
&&
1134 prismember(&trace
, what
)) {
1136 my_realloc(pri
->exec_string
,
1137 strlen(pri
->sys_string
) + 1,
1139 (void) strcpy(pri
->exec_pname
,
1141 (void) strcpy(pri
->exec_string
,
1143 pri
->length
+= strlen(pri
->sys_string
);
1144 pri
->exec_lwpid
= Lsp
->pr_lwpid
;
1147 *pri
->sys_string
= '\0';
1150 if (dotrace
&& (cflag
|| Eflag
) &&
1151 prismember(&trace
, what
)) {
1152 pri
->syslast
= Lsp
->pr_stime
;
1156 if (dotrace
&& Tflag
&& !first
&&
1157 (prismember(&syshang
, what
) ||
1158 (exit_called
&& prismember(&syshang
, SYS_exit
))))
1159 leave_it_hung
= TRUE
;
1162 /* check for write open of a /proc file */
1163 if (what
== SYS_openat
|| what
== SYS_openat64
||
1164 what
== SYS_open
|| what
== SYS_open64
) {
1167 (void) sysentry(pri
, dotrace
);
1168 pri
->Errno
= Lsp
->pr_errno
;
1169 pri
->ErrPriv
= Lsp
->pr_errpriv
;
1171 ((what
== SYS_openat
||
1172 what
== SYS_openat64
) &&
1173 pri
->sys_nargs
> 2 &&
1174 (pri
->sys_args
[2]&0x3) == O_RDONLY
) ||
1175 ((what
== SYS_open
||
1176 what
== SYS_open64
) &&
1177 pri
->sys_nargs
> 1 &&
1178 (pri
->sys_args
[1]&0x3) == O_RDONLY
);
1179 if ((pri
->Errno
== 0 || pri
->Errno
== EBUSY
) &&
1180 pri
->sys_valid
&& !readonly
) {
1181 int rv
= checkproc(pri
);
1182 if (rv
== 1 && Fflag
!= PGRAB_FORCE
) {
1184 * The process opened itself
1185 * and no -F flag was specified.
1186 * Just print the open() call
1187 * and let go of the process.
1189 if (dotrace
&& !cflag
&&
1190 prismember(&trace
, what
)) {
1193 (void) printf("%s\n",
1198 (void) mutex_unlock(
1204 * Process opened someone else.
1205 * The open is being reissued.
1206 * Don't report this one.
1209 *pri
->sys_string
= '\0';
1215 if (what
== SYS_execve
&& pri
->Errno
== 0) {
1217 * Refresh the data model on exec() in case it
1218 * is different from the parent. Lwait()
1219 * doesn't update process-wide status, so we
1220 * have to explicitly call Pstopstatus() to get
1223 (void) Pstopstatus(Proc
, PCNULL
, 0);
1224 data_model
= Psp
->pr_dmodel
;
1226 if (sysexit(pri
, dotrace
))
1228 if (what
== SYS_lwp_create
&& pri
->Rval1
!= 0) {
1229 struct ps_lwphandle
*new_Lwp
;
1232 if ((new_Lwp
= grab_lwp(pri
->Rval1
)) != NULL
) {
1233 (void) thr_sigsetmask(SIG_SETMASK
,
1235 if (thr_create(NULL
, 0, worker_thread
,
1236 new_Lwp
, THR_BOUND
| THR_SUSPENDED
,
1238 abend("cannot create lwp ",
1239 "to follow child lwp");
1240 insert_lwpid(lwpid
);
1241 (void) thr_continue(lwpid
);
1242 (void) thr_sigsetmask(SIG_SETMASK
,
1247 if (dotrace
&& Tflag
&& !first
&&
1248 prismember(&syshang
, what
))
1249 leave_it_hung
= TRUE
;
1250 if (what
== SYS_execve
&& pri
->Errno
== 0) {
1251 is_vfork_child
= FALSE
;
1252 reset_breakpoints();
1254 * exec() resets the calling LWP's lwpid to 1.
1255 * If the LWP has changed its lwpid, then
1256 * we have to free and re-grab the LWP
1257 * in order to keep libproc consistent.
1258 * This "cannot fail".
1260 if (who
!= Lsp
->pr_lwpid
) {
1262 * We must wait for all of our
1263 * siblings to terminate.
1265 while (truss_nlwp
> 1)
1266 (void) cond_wait(&truss_cv
,
1268 who
= Lsp
->pr_lwpid
;
1271 Lgrab(Proc
, who
, &gcode
);
1273 abend("Lgrab error: ",
1274 Lgrab_error(gcode
));
1275 pri
->lwpstat
= Lsp
= Lstatus(Lwp
);
1281 (void) fprintf(stderr
,
1282 "unknown reason for stopping: %d/%d\n",
1287 if (pri
->child
) { /* controlled process fork()ed */
1288 if (fflag
|| Dynpat
!= NULL
) {
1289 if (Lsp
->pr_why
== PR_SYSEXIT
&&
1290 (Lsp
->pr_what
== SYS_vfork
||
1291 (Lsp
->pr_what
== SYS_forksys
&&
1292 Lsp
->pr_sysarg
[0] == 2))) {
1293 is_vfork_child
= TRUE
;
1294 (void) Pstop(Proc
, 0);
1296 if (control(pri
, pri
->child
)) {
1297 (void) mutex_unlock(&truss_lock
);
1301 * If this is vfork(), then
1302 * this clears the breakpoints
1303 * in the parent's address space
1304 * as well as in the child's.
1306 clear_breakpoints();
1307 Prelease(Proc
, PRELEASE_CLEAR
);
1315 * Here, we are still the parent truss.
1316 * If the child messes with the breakpoints and
1317 * this is vfork(), we have to set them again.
1319 if (Dynpat
!= NULL
&& is_vfork_child
&& !fflag
)
1321 is_vfork_child
= FALSE
;
1326 if (leave_it_hung
) {
1327 (void) mutex_unlock(&truss_lock
);
1333 * To recover from vfork, we must catch the lwp
1334 * that issued the vfork() when it returns to user
1335 * level, with all other lwps remaining stopped.
1336 * For this purpose, we have directed all lwps to
1337 * stop and we now set the vfork()ing lwp running
1338 * with the PRSTEP flag. We expect to capture it
1339 * when it stops again showing PR_FAULTED/FLTTRACE.
1340 * We are holding truss_lock, so no other threads
1341 * in truss will set any other lwps in the victim
1344 reset_traps
= FALSE
;
1345 (void) Lsetrun(Lwp
, 0, PRSTEP
);
1347 (void) Lwait(Lwp
, 0);
1348 } while (Lstate(Lwp
) == PS_RUN
);
1349 if (Lstate(Lwp
) == PS_STOP
&&
1350 Lsp
->pr_why
== PR_FAULTED
&&
1351 Lsp
->pr_what
== FLTTRACE
) {
1352 reestablish_traps();
1353 (void) Lsetrun(Lwp
, 0, PRCFAULT
|PRSTOP
);
1355 (void) printf("%s\t*** Expected PR_FAULTED/"
1356 "FLTTRACE stop following vfork()\n",
1361 if (Lstate(Lwp
) == PS_STOP
) {
1364 if (interrupt
| sigusr1
) {
1365 (void) mutex_unlock(&truss_lock
);
1369 * If we must leave this lwp hung is sympathy with
1370 * another lwp that is being left hung on purpose,
1371 * then push the state onward toward PR_REQUESTED.
1374 if (Lsp
->pr_why
== PR_REQUESTED
) {
1375 (void) mutex_unlock(&truss_lock
);
1380 if (Lsetrun(Lwp
, 0, flags
) != 0 &&
1381 Lstate(Lwp
) != PS_LOST
&&
1382 Lstate(Lwp
) != PS_UNDEAD
) {
1383 (void) mutex_unlock(&truss_lock
);
1385 abend("cannot start subject lwp", NULL
);
1391 (void) mutex_unlock(&truss_lock
);
1395 /* block all signals in preparation for exiting */
1396 (void) thr_sigsetmask(SIG_SETMASK
, &fillset
, NULL
);
1398 if (Lstate(Lwp
) == PS_UNDEAD
|| Lstate(Lwp
) == PS_LOST
)
1399 (void) mutex_lock(&truss_lock
);
1401 (void) Lstop(Lwp
, MILLISEC
);
1402 (void) mutex_lock(&truss_lock
);
1403 if (Lstate(Lwp
) == PS_STOP
&&
1404 Lsp
->pr_why
== PR_FAULTED
&&
1405 Lsp
->pr_what
== FLTBPT
)
1406 (void) function_trace(pri
, 0, 1, dotrace
);
1409 if (dotrace
&& ow_in_effect
) {
1411 (void) mutex_lock(&count_lock
);
1412 scp
= Cp
->syscount
[ow_syscall
];
1413 if (ow_subcode
!= -1)
1416 accumulate(&scp
->stime
,
1417 &Lsp
->pr_stime
, &pri
->syslast
);
1418 accumulate(&Cp
->usrtotal
,
1419 &Lsp
->pr_utime
, &pri
->usrlast
);
1420 pri
->syslast
= Lsp
->pr_stime
;
1421 pri
->usrlast
= Lsp
->pr_utime
;
1422 (void) mutex_unlock(&count_lock
);
1426 (void) printf("%s\n", ow_string
);
1429 pri
->syslast
= Lsp
->pr_stime
;
1432 Psetsysentry(Proc
, &running_set
);
1435 if (Lstate(Lwp
) == PS_UNDEAD
|| Lstate(Lwp
) == PS_LOST
) {
1437 * The victim thread has exited or we lost control of
1438 * the process. Remove ourself from the list of all
1439 * truss threads and notify everyone waiting for this.
1441 lwpid_t my_id
= thr_self();
1444 for (i
= 0; i
< truss_maxlwp
; i
++) {
1445 if (truss_lwpid
[i
] == my_id
) {
1450 if (--truss_nlwp
!= 0) {
1451 (void) cond_broadcast(&truss_cv
);
1454 * The last truss worker thread is terminating.
1455 * The address space is gone (UNDEAD) or is
1456 * inaccessible (LOST) so we cannot clear the
1457 * breakpoints. Just report the htable stats.
1459 report_htable_stats();
1463 * The victim thread is not a zombie thread, and we have not
1464 * lost control of the process. We must have gotten here due
1465 * to (leave_hung || leave_it_hung || interrupt || sigusr1).
1466 * In these cases, we must carefully uninstrument the process
1467 * and either set it running or leave it stopped and abandoned.
1469 static int nstopped
= 0;
1470 static int cleared
= 0;
1474 if ((leave_hung
| interrupt
| sigusr1
) == 0)
1475 abend("(leave_hung | interrupt | sigusr1) == 0", NULL
);
1478 * The first truss thread through here needs to instruct all
1479 * application threads to stop -- they're not necessarily
1480 * going to stop on their own.
1482 if (nstopped
++ == 0)
1483 (void) Pdstop(Proc
);
1486 * Notify all other worker threads about the reason
1487 * for being here (leave_hung || interrupt || sigusr1).
1489 broadcast_signals();
1492 * Once the last thread has reached this point, then and
1493 * only then is it safe to remove breakpoints and other
1494 * instrumentation. Since breakpoints are executed without
1495 * truss_lock held, a monitor thread can't exit until all
1496 * breakpoints have been removed, and we can't be sure the
1497 * procedure to execute a breakpoint won't temporarily
1498 * reinstall a breakpont. Accordingly, we need to wait
1499 * until all threads are in a known state.
1501 while (nstopped
!= truss_nlwp
)
1502 (void) cond_wait(&truss_cv
, &truss_lock
);
1505 * All truss threads have reached this point.
1506 * One of them clears the breakpoints and
1507 * wakes up everybody else to finish up.
1509 if (cleared
++ == 0) {
1511 * All threads should already be stopped,
1512 * but just to be safe...
1514 (void) Pstop(Proc
, MILLISEC
);
1515 clear_breakpoints();
1516 (void) Psysexit(Proc
, SYS_vfork
, FALSE
);
1517 (void) Psysexit(Proc
, SYS_forksys
, FALSE
);
1518 (void) Punsetflags(Proc
, PR_FORK
);
1521 (void) cond_broadcast(&truss_cv
);
1524 if (!leave_hung
&& Lstate(Lwp
) == PS_STOP
)
1525 (void) Lsetrun(Lwp
, 0, 0);
1529 (void) mutex_unlock(&truss_lock
);
1534 * Give a base date for time stamps, adjusted to the
1535 * stop time of the selected (first or created) process.
1538 setup_basetime(hrtime_t basehrtime
, struct timeval
*basedate
)
1540 const pstatus_t
*Psp
= Pstatus(Proc
);
1541 (void) mutex_lock(&count_lock
);
1542 Cp
->basetime
= Psp
->pr_lwp
.pr_tstamp
;
1543 (void) mutex_unlock(&count_lock
);
1545 if ((dflag
|Dflag
) && !cflag
) {
1546 const struct tm
*ptm
;
1549 hrtime_t delta
= basehrtime
-
1550 ((hrtime_t
)Cp
->basetime
.tv_sec
* NANOSEC
+
1551 Cp
->basetime
.tv_nsec
);
1554 basedate
->tv_sec
-= (time_t)(delta
/ NANOSEC
);
1555 basedate
->tv_usec
-= (delta
% NANOSEC
) / 1000;
1556 if (basedate
->tv_usec
< 0) {
1558 basedate
->tv_usec
+= MICROSEC
;
1561 ptm
= localtime(&basedate
->tv_sec
);
1562 ptime
= asctime(ptm
);
1563 if ((pdst
= tzname
[ptm
->tm_isdst
? 1 : 0]) == NULL
)
1567 "Base time stamp: %ld.%4.4ld [ %.20s%s %.4s ]\n",
1568 basedate
->tv_sec
, basedate
->tv_usec
/ 100,
1569 ptime
, pdst
, ptime
+ 20);
1576 * Performs per-process initializations. If truss is following a victim
1577 * process it will fork additional truss processes to follow new processes
1578 * created. Here is where each new truss process gets its per-process data
1586 struct timeval basedate
;
1587 hrtime_t basehrtime
;
1588 struct syscount
*scp
;
1590 timestruc_t c_basetime
;
1592 /* Make sure we only configure the basetime for the first truss proc */
1595 pmem
= my_malloc(sizeof (struct counts
) + maxsyscalls() *
1596 sizeof (struct syscount
), NULL
);
1597 Cp
= (struct counts
*)pmem
;
1598 basehrtime
= gethrtime();
1599 (void) gettimeofday(&basedate
, NULL
);
1600 setup_basetime(basehrtime
, &basedate
);
1603 c_basetime
= Cp
->basetime
;
1605 (void) memset(Cp
, 0, sizeof (struct counts
) + maxsyscalls() *
1606 sizeof (struct syscount
));
1608 Cp
->basetime
= c_basetime
;
1610 if (fcall_tbl
!= NULL
)
1611 destroy_hash(fcall_tbl
);
1612 fcall_tbl
= init_hash(4096);
1614 (void) mutex_lock(&count_lock
);
1615 scp
= (struct syscount
*)(Cp
+ 1);
1616 for (i
= 0; i
<= PRMAXSYS
; i
++) {
1617 Cp
->syscount
[i
] = scp
;
1618 scp
+= nsubcodes(i
);
1620 (void) mutex_unlock(&count_lock
);
1625 * Writes child state to a tempfile where it can be read and
1626 * accumulated by the parent process. The file descriptor is shared
1627 * among the processes. Ordering of writes does not matter, it is, however,
1628 * necessary to ensure that all writes are atomic.
1639 unsigned char *buf
= NULL
;
1644 /* ensure that we are in fact a child process */
1648 /* enumerate fcall_tbl (tbl locked until freed) */
1649 if (Dynpat
!= NULL
) {
1650 itr
= iterate_hash(fcall_tbl
);
1652 ntry
= iter_next(itr
);
1653 while (ntry
!= NULL
) {
1654 fentry
.type
= HD_hashntry
;
1655 fentry
.count
= ntry
->count
;
1662 if (i
+ sizeof (fentry
) > bufsz
) {
1663 buf
= my_realloc(buf
, i
+ j
+ sizeof (fentry
),
1665 bufsz
= i
+ j
+ sizeof (fentry
);
1667 (void) memcpy(buf
, &fentry
, sizeof (fentry
));
1668 (void) strlcpy((char *)(buf
+ sizeof (fentry
)), t
, j
);
1669 (void) strlcpy((char *)(buf
+ sizeof (fentry
) + j
),
1671 if (write(sfd
, buf
, sizeof (fentry
) + i
+ j
) == -1)
1672 abend("Error writing to tmp file", NULL
);
1673 ntry
= iter_next(itr
);
1678 /* Now write the count/syscount structs down */
1679 bufsz
= sizeof (fentry
) + (sizeof (struct counts
) + maxsyscalls() *
1680 sizeof (struct syscount
));
1681 buf
= my_realloc(buf
, bufsz
, NULL
);
1682 fentry
.type
= HD_cts_syscts
;
1683 fentry
.count
= 0; /* undefined, really */
1684 fentry
.sz_key
= bufsz
- sizeof (fentry
);
1685 fentry
.sz_lib
= 0; /* also undefined */
1686 (void) memcpy(buf
, &fentry
, sizeof (fentry
));
1687 (void) memcpy((char *)(buf
+ sizeof (fentry
)), Cp
,
1688 bufsz
- sizeof (fentry
));
1689 if (write(sfd
, buf
, bufsz
) == -1)
1690 abend("Error writing cts/syscts to tmpfile", NULL
);
1696 * The following reads entries from the tempfile back to the parent
1697 * so that information can be collected and summed for overall statistics.
1698 * This reads records out of the tempfile. If they are hash table entries,
1699 * the record is merged with the hash table kept by the parent process.
1700 * If the information is a struct count/struct syscount pair, they are
1701 * copied and added into the count/syscount array kept by the parent.
1710 size_t c_offset
= 0;
1719 if (fstat(sfd
, &fsi
) == -1)
1720 abend("Error stat-ing tempfile", NULL
);
1721 filesz
= fsi
.st_size
;
1723 while (c_offset
< filesz
) {
1724 /* first get hdntry */
1725 if (pread(sfd
, &ntry
, sizeof (hdntry_t
), c_offset
) !=
1727 abend("Unable to perform full read of hdntry", NULL
);
1728 c_offset
+= sizeof (hdntry_t
);
1730 switch (ntry
.type
) {
1733 /* first get lib string */
1734 if (ntry
.sz_lib
> t_strsz
) {
1735 t
= my_realloc(t
, ntry
.sz_lib
, NULL
);
1736 t_strsz
= ntry
.sz_lib
;
1739 (void) memset(t
, 0, t_strsz
);
1741 /* now actually get the string */
1742 if (pread(sfd
, t
, ntry
.sz_lib
, c_offset
) != ntry
.sz_lib
)
1743 abend("Unable to perform full read of lib str",
1745 c_offset
+= ntry
.sz_lib
;
1747 /* now get key string */
1749 if (ntry
.sz_key
> s_strsz
) {
1750 s
= my_realloc(s
, ntry
.sz_key
, NULL
);
1751 s_strsz
= ntry
.sz_key
;
1753 (void) memset(s
, 0, s_strsz
);
1754 if (pread(sfd
, s
, ntry
.sz_key
, c_offset
) != ntry
.sz_key
)
1755 abend("Unable to perform full read of key str",
1757 c_offset
+= ntry
.sz_key
;
1759 add_fcall(fcall_tbl
, t
, s
, ntry
.count
);
1765 size_t bfsz
= sizeof (struct counts
) + maxsyscalls()
1766 * sizeof (struct syscount
);
1768 struct syscount
*sscp
;
1770 if (ntry
.sz_key
!= bfsz
)
1771 abend("cts/syscts size does not sanity check",
1773 ncp
= my_malloc(ntry
.sz_key
, NULL
);
1775 if (pread(sfd
, ncp
, ntry
.sz_key
, c_offset
) !=
1777 abend("Unable to perform full read of cts",
1779 c_offset
+= ntry
.sz_key
;
1781 sscp
= (struct syscount
*)(ncp
+ 1);
1783 (void) mutex_lock(&count_lock
);
1785 Cp
->usrtotal
.tv_sec
+= ncp
->usrtotal
.tv_sec
;
1786 Cp
->usrtotal
.tv_nsec
+= ncp
->usrtotal
.tv_nsec
;
1787 if (Cp
->usrtotal
.tv_nsec
>= NANOSEC
) {
1788 Cp
->usrtotal
.tv_nsec
-= NANOSEC
;
1789 Cp
->usrtotal
.tv_sec
++;
1791 for (i
= 0; i
<= PRMAXSYS
; i
++) {
1792 ncp
->syscount
[i
] = sscp
;
1793 sscp
+= nsubcodes(i
);
1796 for (i
= 0; i
<= PRMAXFAULT
; i
++) {
1797 Cp
->fltcount
[i
] += ncp
->fltcount
[i
];
1800 for (i
= 0; i
<= PRMAXSIG
; i
++) {
1801 Cp
->sigcount
[i
] += ncp
->sigcount
[i
];
1804 for (i
= 0; i
<= PRMAXSYS
; i
++) {
1805 struct syscount
*scp
= Cp
->syscount
[i
];
1806 struct syscount
*nscp
= ncp
->syscount
[i
];
1807 int n
= nsubcodes(i
);
1810 for (subcode
= 0; subcode
< n
; subcode
++,
1812 scp
->count
+= nscp
->count
;
1813 scp
->error
+= nscp
->error
;
1814 scp
->stime
.tv_sec
+= nscp
->stime
.tv_sec
;
1815 scp
->stime
.tv_nsec
+=
1816 nscp
->stime
.tv_nsec
;
1817 if (scp
->stime
.tv_nsec
>= NANOSEC
) {
1818 scp
->stime
.tv_nsec
-= NANOSEC
;
1819 scp
->stime
.tv_sec
++;
1823 (void) mutex_unlock(&count_lock
);
1829 abend("Unknown file entry type encountered", NULL
);
1834 if (fstat(sfd
, &fsi
) == -1)
1835 abend("Error stat-ing tempfile", NULL
);
1836 filesz
= fsi
.st_size
;
1845 make_pname(private_t
*pri
, id_t tid
)
1848 int ff
= (fflag
|| ngrab
> 1);
1849 int lf
= (lflag
| tid
| (Thr_agent
!= NULL
) | (truss_nlwp
> 1));
1850 pid_t pid
= Pstatus(Proc
)->pr_pid
;
1851 id_t lwpid
= pri
->lwpstat
->pr_lwpid
;
1853 if (ff
!= pri
->pparam
.ff
||
1854 lf
!= pri
->pparam
.lf
||
1855 pid
!= pri
->pparam
.pid
||
1856 lwpid
!= pri
->pparam
.lwpid
||
1857 tid
!= pri
->pparam
.tid
) {
1858 char *s
= pri
->pname
;
1861 s
+= sprintf(s
, "%d", (int)pid
);
1863 s
+= sprintf(s
, "/%d", (int)lwpid
);
1865 s
+= sprintf(s
, "@%d", (int)tid
);
1867 *s
++ = ':', *s
++ = '\t';
1868 if (ff
&& lf
&& s
< pri
->pname
+ 9)
1871 pri
->pparam
.ff
= ff
;
1872 pri
->pparam
.lf
= lf
;
1873 pri
->pparam
.pid
= pid
;
1874 pri
->pparam
.lwpid
= lwpid
;
1875 pri
->pparam
.tid
= tid
;
1881 * Print the pri->pname[] string, if any.
1884 putpname(private_t
*pri
)
1887 (void) fputs(pri
->pname
, stdout
);
1891 * Print the timestamp, if requested (-d, -D, or -E).
1894 timestamp(private_t
*pri
)
1896 const lwpstatus_t
*Lsp
= pri
->lwpstat
;
1900 if (!(dflag
|Dflag
|Eflag
) || !(Lsp
->pr_flags
& PR_STOPPED
))
1903 seconds
= Lsp
->pr_tstamp
.tv_sec
- Cp
->basetime
.tv_sec
;
1904 fraction
= Lsp
->pr_tstamp
.tv_nsec
- Cp
->basetime
.tv_nsec
;
1907 fraction
+= NANOSEC
;
1909 /* fraction in 1/10 milliseconds, rounded up */
1910 fraction
= (fraction
+ 50000) / 100000;
1911 if (fraction
>= (MILLISEC
* 10)) {
1913 fraction
-= (MILLISEC
* 10);
1916 if (dflag
) /* time stamp */
1917 (void) printf("%2d.%4.4d\t", seconds
, fraction
);
1919 if (Dflag
) { /* time delta */
1920 int oseconds
= pri
->seconds
;
1921 int ofraction
= pri
->fraction
;
1923 pri
->seconds
= seconds
;
1924 pri
->fraction
= fraction
;
1925 seconds
-= oseconds
;
1926 fraction
-= ofraction
;
1929 fraction
+= (MILLISEC
* 10);
1931 (void) printf("%2d.%4.4d\t", seconds
, fraction
);
1935 seconds
= Lsp
->pr_stime
.tv_sec
- pri
->syslast
.tv_sec
;
1936 fraction
= Lsp
->pr_stime
.tv_nsec
- pri
->syslast
.tv_nsec
;
1940 fraction
+= NANOSEC
;
1942 /* fraction in 1/10 milliseconds, rounded up */
1943 fraction
= (fraction
+ 50000) / 100000;
1944 if (fraction
>= (MILLISEC
* 10)) {
1946 fraction
-= (MILLISEC
* 10);
1948 (void) printf("%2d.%4.4d\t", seconds
, fraction
);
1953 * Create output file, being careful about
1954 * suid/sgid and file descriptor 0, 1, 2 issues.
1962 if (Euid
== Ruid
&& Egid
== Rgid
) /* not set-id */
1963 fd
= creat(path
, mode
);
1964 else if (access(path
, F_OK
) != 0) { /* file doesn't exist */
1965 /* if directory permissions OK, create file & set ownership */
1971 /* generate path for directory containing file */
1972 if ((p
= strrchr(path
, '/')) == NULL
) { /* no '/' */
1974 *p
++ = '.'; /* current directory */
1976 } else if (p
== path
) { /* leading '/' */
1978 *p
++ = '/'; /* root directory */
1980 } else { /* embedded '/' */
1981 dir
= path
; /* directory path */
1985 if (access(dir
, W_OK
|X_OK
) != 0) {
1986 /* not writeable/searchable */
1989 } else { /* create file and set ownership correctly */
1991 if ((fd
= creat(path
, mode
)) >= 0)
1992 (void) chown(path
, (int)Ruid
, (int)Rgid
);
1994 } else if (access(path
, W_OK
) != 0) /* file not writeable */
1997 fd
= creat(path
, mode
);
2000 * Make sure it's not one of 0, 1, or 2.
2001 * This allows truss to work when spawned by init(1m).
2003 if (0 <= fd
&& fd
<= 2) {
2004 int dfd
= fcntl(fd
, F_DUPFD
, 3);
2010 * Mark it close-on-exec so created processes don't inherit it.
2013 (void) fcntl(fd
, F_SETFD
, FD_CLOEXEC
);
2023 (void) fcntl(2, F_DUPFD
, 1);
2024 } else if (ofd
!= 1) {
2026 (void) fcntl(ofd
, F_DUPFD
, 1);
2028 /* if no stderr, make it the same file */
2029 if ((ofd
= dup(2)) < 0)
2030 (void) fcntl(1, F_DUPFD
, 2);
2037 * Accumulate time differencies: a += e - s;
2040 accumulate(timestruc_t
*ap
, const timestruc_t
*ep
, const timestruc_t
*sp
)
2042 ap
->tv_sec
+= ep
->tv_sec
- sp
->tv_sec
;
2043 ap
->tv_nsec
+= ep
->tv_nsec
- sp
->tv_nsec
;
2044 if (ap
->tv_nsec
>= NANOSEC
) {
2045 ap
->tv_nsec
-= NANOSEC
;
2047 } else if (ap
->tv_nsec
< 0) {
2048 ap
->tv_nsec
+= NANOSEC
;
2054 lib_sort(const void *p1
, const void *p2
)
2060 hentry_t
*t1
= (hentry_t
*)p1
;
2061 hentry_t
*t2
= (hentry_t
*)p2
;
2066 if ((cmpr
= strcmp(p
, q
)) == 0) {
2076 return (strcmp(p
, q
));
2083 report(private_t
*pri
, time_t lapse
) /* elapsed time, clock ticks */
2091 timestruc_t tickzero
;
2093 timestruc_t ticktot
;
2098 for (i
= 0, total
= 0; i
<= PRMAXFAULT
&& !interrupt
; i
++) {
2099 if ((count
= Cp
->fltcount
[i
]) != 0) {
2100 if (total
== 0) /* produce header */
2101 (void) printf("faults -------------\n");
2103 name
= proc_fltname(i
, pri
->flt_name
,
2104 sizeof (pri
->flt_name
));
2106 (void) printf("%s%s\t%4ld\n", name
,
2107 (((int)strlen(name
) < 8)?
2108 (const char *)"\t" : (const char *)""),
2113 if (total
&& !interrupt
)
2114 (void) printf("total:\t\t%4ld\n\n", total
);
2116 for (i
= 0, total
= 0; i
<= PRMAXSIG
&& !interrupt
; i
++) {
2117 if ((count
= Cp
->sigcount
[i
]) != 0) {
2118 if (total
== 0) /* produce header */
2119 (void) printf("signals ------------\n");
2120 name
= signame(pri
, i
);
2121 (void) printf("%s%s\t%4ld\n", name
,
2122 (((int)strlen(name
) < 8)?
2123 (const char *)"\t" : (const char *)""),
2128 if (total
&& !interrupt
)
2129 (void) printf("total:\t\t%4ld\n\n", total
);
2131 if ((Dynpat
!= NULL
) && !interrupt
) {
2132 size_t elem
= elements_in_table(fcall_tbl
);
2133 hiter_t
*itr
= iterate_hash(fcall_tbl
);
2134 hentry_t
*tmp
= iter_next(itr
);
2135 hentry_t
*stbl
= my_malloc(elem
* sizeof (hentry_t
), NULL
);
2137 while ((tmp
!= NULL
) && (i
< elem
)) {
2138 stbl
[i
].prev
= tmp
->prev
;
2139 stbl
[i
].next
= tmp
->next
;
2140 stbl
[i
].lib
= tmp
->lib
;
2141 stbl
[i
].key
= tmp
->key
;
2142 stbl
[i
].count
= tmp
->count
;
2143 tmp
= iter_next(itr
);
2146 qsort((void *)stbl
, elem
, sizeof (hentry_t
),
2149 "\n%-20s %-40s %s\n", "Library:", "Function", "calls");
2150 for (i
= 0; i
< elem
; i
++) {
2151 (void) printf("%-20s %-40s %ld\n", stbl
[i
].lib
,
2152 stbl
[i
].key
, stbl
[i
].count
);
2161 "\nsyscall seconds calls errors\n");
2164 tickzero
.tv_sec
= ticks
.tv_sec
= ticktot
.tv_sec
= 0;
2165 tickzero
.tv_nsec
= ticks
.tv_nsec
= ticktot
.tv_nsec
= 0;
2166 for (i
= 0; i
<= PRMAXSYS
&& !interrupt
; i
++) {
2167 struct syscount
*scp
= Cp
->syscount
[i
];
2168 int n
= nsubcodes(i
);
2171 for (subcode
= 0; subcode
< n
; subcode
++, scp
++) {
2172 if ((count
= scp
->count
) != 0 || scp
->error
) {
2173 (void) printf("%-19.19s ",
2174 sysname(pri
, i
, subcode
));
2177 accumulate(&ticktot
, &ticks
, &tickzero
);
2180 (void) printf(" %7ld", count
);
2181 if ((error
= scp
->error
) != 0)
2182 (void) printf(" %7ld", error
);
2183 (void) fputc('\n', stdout
);
2192 " -------- ------ ----\n");
2193 (void) printf("sys totals: ");
2195 (void) printf(" %7ld %6ld\n", total
, errtot
);
2199 (void) printf("usr time: ");
2200 prtim(&Cp
->usrtotal
);
2201 (void) fputc('\n', stdout
);
2205 int hz
= (int)sysconf(_SC_CLK_TCK
);
2207 ticks
.tv_sec
= lapse
/ hz
;
2208 ticks
.tv_nsec
= (lapse
% hz
) * (1000000000 / hz
);
2209 (void) printf("elapsed: ");
2211 (void) fputc('\n', stdout
);
2216 prtim(timestruc_t
*tp
)
2220 if ((sec
= tp
->tv_sec
) != 0) /* whole seconds */
2221 (void) printf("%5lu", sec
);
2225 (void) printf(".%3.3ld", tp
->tv_nsec
/1000000); /* fraction */
2229 * Gather process id's.
2230 * Return 0 on success, != 0 on failure.
2233 pids(char *arg
, proc_set_t
*grab
)
2237 const char *lwps
= NULL
;
2239 if ((pid
= proc_arg_xpsinfo(arg
, PR_ARG_PIDS
, NULL
, &i
, &lwps
)) < 0) {
2240 (void) fprintf(stderr
, "%s: cannot trace '%s': %s\n",
2241 command
, arg
, Pgrab_error(i
));
2245 for (i
= 0; i
< ngrab
; i
++)
2246 if (grab
[i
].pid
== pid
) /* duplicate */
2250 grab
[ngrab
].pid
= pid
;
2251 grab
[ngrab
].lwps
= lwps
;
2254 (void) fprintf(stderr
, "%s: duplicate process-id ignored: %d\n",
2260 * Report psargs string.
2263 psargs(private_t
*pri
)
2265 pid_t pid
= Pstatus(Proc
)->pr_pid
;
2268 if (proc_get_psinfo(pid
, &psinfo
) == 0)
2269 (void) printf("%spsargs: %.64s\n",
2270 pri
->pname
, psinfo
.pr_psargs
);
2273 (void) printf("%s\t*** Cannot read psinfo file for pid %d\n",
2274 pri
->pname
, (int)pid
);
2279 fetchstring(private_t
*pri
, long addr
, int maxleng
)
2286 if (pri
->str_bsize
== 0) /* initial allocation of string buffer */
2288 my_malloc(pri
->str_bsize
= 16, "string buffer");
2289 *pri
->str_buffer
= '\0';
2291 for (nbyte
= 40; nbyte
== 40 && leng
< maxleng
; addr
+= 40) {
2292 if ((nbyte
= Pread(Proc
, string
, 40, addr
)) <= 0)
2293 return (leng
? pri
->str_buffer
: NULL
);
2295 (nbyte
= strlen(string
)) > 0) {
2296 while (leng
+ nbyte
>= pri
->str_bsize
)
2298 my_realloc(pri
->str_buffer
,
2299 pri
->str_bsize
*= 2, "string buffer");
2300 (void) strcpy(pri
->str_buffer
+leng
, string
);
2307 pri
->str_buffer
[leng
] = '\0';
2309 return (pri
->str_buffer
);
2313 getset(prpriv_t
*p
, priv_ptype_t set
)
2315 return ((priv_set_t
*)
2316 &p
->pr_sets
[priv_getsetbyname(set
) * p
->pr_setsize
]);
2320 show_cred(private_t
*pri
, int new, int loadonly
)
2325 if (proc_get_cred(Pstatus(Proc
)->pr_pid
, &cred
, 0) < 0) {
2326 perror("show_cred() - credential");
2327 (void) printf("%s\t*** Cannot get credentials\n", pri
->pname
);
2330 if ((privs
= proc_get_priv(Pstatus(Proc
)->pr_pid
)) == NULL
) {
2331 perror("show_cred() - privileges");
2332 (void) printf("%s\t*** Cannot get privileges\n", pri
->pname
);
2336 if (!loadonly
&& !cflag
&& prismember(&trace
, SYS_execve
)) {
2339 if ((new && cred
.pr_ruid
!= cred
.pr_suid
) ||
2340 cred
.pr_ruid
!= credentials
.pr_ruid
||
2341 cred
.pr_suid
!= credentials
.pr_suid
)
2343 "%s *** SUID: ruid/euid/suid = %d / %d / %d ***\n",
2348 if ((new && cred
.pr_rgid
!= cred
.pr_sgid
) ||
2349 cred
.pr_rgid
!= credentials
.pr_rgid
||
2350 cred
.pr_sgid
!= credentials
.pr_sgid
)
2352 "%s *** SGID: rgid/egid/sgid = %d / %d / %d ***\n",
2357 if (privdata
!= NULL
&& cred
.pr_euid
!= 0) {
2358 priv_set_t
*npset
= getset(privs
, PRIV_PERMITTED
);
2359 priv_set_t
*opset
= getset(privdata
, PRIV_PERMITTED
);
2361 if (!priv_issubset(npset
, opset
)) {
2362 /* Use the to be freed privdata as scratch */
2363 priv_inverse(opset
);
2364 priv_intersect(npset
, opset
);
2365 s
= priv_set_to_str(opset
, ',', PRIV_STR_SHORT
);
2366 t
= priv_set_to_str(npset
, ',', PRIV_STR_SHORT
);
2367 (void) printf("%s *** FPRIV: P/E: %s ***\n",
2369 strlen(s
) > strlen(t
) ? t
: s
);
2376 if (privdata
!= NULL
)
2377 proc_free_priv(privdata
);
2383 * Take control of a child process.
2384 * We come here with truss_lock held.
2387 control(private_t
*pri
, pid_t pid
)
2389 const pstatus_t
*Psp
;
2390 const lwpstatus_t
*Lsp
;
2395 (void) mutex_lock(&gps
->fork_lock
);
2396 while (gps
->fork_pid
!= 0)
2397 (void) cond_wait(&gps
->fork_cv
, &gps
->fork_lock
);
2398 gps
->fork_pid
= getpid(); /* parent pid */
2399 if ((childpid
= fork()) == -1) {
2400 (void) printf("%s\t*** Cannot fork() to control process #%d\n",
2401 pri
->pname
, (int)pid
);
2404 (void) cond_broadcast(&gps
->fork_cv
);
2405 (void) mutex_unlock(&gps
->fork_lock
);
2410 if (childpid
!= 0) {
2412 * The parent carries on, after a brief pause.
2413 * The parent must wait until the child executes procadd(pid).
2415 while (gps
->fork_pid
!= childpid
)
2416 (void) cond_wait(&gps
->fork_cv
, &gps
->fork_lock
);
2418 (void) cond_broadcast(&gps
->fork_cv
);
2419 (void) mutex_unlock(&gps
->fork_lock
);
2423 childpid
= getpid();
2425 exit_called
= FALSE
;
2426 Pfree(Proc
); /* forget old process */
2429 * The parent process owns the shared gps->fork_lock.
2430 * The child must grab it again.
2432 (void) mutex_lock(&gps
->fork_lock
);
2435 * Child grabs the process and retains the tracing flags.
2437 if ((Proc
= Pgrab(pid
, PGRAB_RETAIN
, &rc
)) == NULL
) {
2438 (void) fprintf(stderr
,
2439 "%s: cannot control child process, pid# %d: %s\n",
2440 command
, (int)pid
, Pgrab_error(rc
));
2441 gps
->fork_pid
= childpid
;
2442 (void) cond_broadcast(&gps
->fork_cv
);
2443 (void) mutex_unlock(&gps
->fork_lock
);
2449 * Add ourself to the set of truss processes
2450 * and notify the parent to carry on.
2453 gps
->fork_pid
= childpid
;
2454 (void) cond_broadcast(&gps
->fork_cv
);
2455 (void) mutex_unlock(&gps
->fork_lock
);
2458 * We may have grabbed the child before it is fully stopped on exit
2459 * from fork. Wait one second (at most) for it to settle down.
2461 (void) Pwait(Proc
, MILLISEC
);
2462 if (Rdb_agent
!= NULL
)
2463 Rdb_agent
= Prd_agent(Proc
);
2465 Psp
= Pstatus(Proc
);
2468 data_model
= Psp
->pr_dmodel
;
2472 pri
->syslast
= Psp
->pr_stime
;
2473 pri
->usrlast
= Psp
->pr_utime
;
2475 flags
= PR_FORK
| PR_ASYNC
;
2477 flags
|= PR_BPTADJ
; /* needed for x86 */
2478 (void) Psetflags(Proc
, flags
);
2484 * Take control of an existing process.
2487 grabit(private_t
*pri
, proc_set_t
*set
)
2489 const pstatus_t
*Psp
;
2490 const lwpstatus_t
*Lsp
;
2494 * Don't force the takeover unless the -F option was specified.
2496 if ((Proc
= Pgrab(set
->pid
, Fflag
, &gcode
)) == NULL
) {
2497 (void) fprintf(stderr
, "%s: %s: %d\n",
2498 command
, Pgrab_error(gcode
), (int)set
->pid
);
2499 pri
->lwpstat
= NULL
;
2502 Psp
= Pstatus(Proc
);
2508 data_model
= Psp
->pr_dmodel
;
2509 pri
->syslast
= Psp
->pr_stime
;
2510 pri
->usrlast
= Psp
->pr_utime
;
2512 if (fflag
|| Dynpat
!= NULL
)
2513 (void) Psetflags(Proc
, PR_FORK
);
2515 (void) Punsetflags(Proc
, PR_FORK
);
2516 procadd(set
->pid
, set
->lwps
);
2517 show_cred(pri
, TRUE
, FALSE
);
2522 * Release process from control.
2525 release(private_t
*pri
, pid_t pid
)
2528 * The process in question is the child of a traced process.
2529 * We are here to turn off the inherited tracing flags.
2538 /* process is freshly forked, no need for exclusive open */
2539 (void) sprintf(ctlname
, "/proc/%d/ctl", (int)pid
);
2540 if ((fd
= open(ctlname
, O_WRONLY
)) < 0 ||
2541 write(fd
, (char *)ctl
, sizeof (ctl
)) < 0) {
2542 perror("release()");
2544 "%s\t*** Cannot release child process, pid# %d\n",
2545 pri
->pname
, (int)pid
);
2548 if (fd
>= 0) /* run-on-last-close sets the process running */
2556 * SIGUSR1 is special. It is used by one truss process to tell
2557 * another truss process to release its controlled process.
2558 * SIGUSR2 is also special. It is used to wake up threads waiting
2559 * for a victim lwp to stop after an event that will leave the
2560 * process hung (stopped and abandoned) has occurred.
2562 if (sig
== SIGUSR1
) {
2564 } else if (sig
== SIGUSR2
) {
2567 struct ps_lwphandle
*Lwp
;
2569 if (thr_getspecific(private_key
, &value
) == 0 &&
2570 (pri
= value
) != NULL
&&
2571 (Lwp
= pri
->Lwp
) != NULL
)
2572 (void) Lstop(Lwp
, MILLISEC
/ 10);
2579 errmsg(const char *s
, const char *q
)
2586 (void) strcpy(msg
, command
);
2587 (void) strcat(msg
, ": ");
2590 (void) strcat(msg
, s
);
2592 (void) strcat(msg
, q
);
2593 (void) strcat(msg
, "\n");
2594 (void) write(2, msg
, (size_t)strlen(msg
));
2599 abend(const char *s
, const char *q
)
2601 (void) thr_sigsetmask(SIG_SETMASK
, &fillset
, NULL
);
2605 clear_breakpoints();
2606 (void) Punsetflags(Proc
, PR_ASYNC
);
2607 Prelease(Proc
, created
? PRELEASE_KILL
: PRELEASE_CLEAR
);
2618 * If allocation fails then print a message and abort.
2621 my_realloc(void *buf
, size_t size
, const char *msg
)
2623 if ((buf
= realloc(buf
, size
)) == NULL
) {
2625 abend("cannot allocate ", msg
);
2627 abend("memory allocation failure", NULL
);
2634 my_calloc(size_t nelem
, size_t elsize
, const char *msg
)
2638 if ((buf
= calloc(nelem
, elsize
)) == NULL
) {
2640 abend("cannot allocate ", msg
);
2642 abend("memory allocation failure", NULL
);
2649 my_malloc(size_t size
, const char *msg
)
2651 return (my_realloc(NULL
, size
, msg
));
2662 for (i
= 0; i
< 10; i
++) {
2663 while ((pid
= wait(&status
)) != -1) {
2664 /* return exit() code of the created process */
2665 if (pid
== created
) {
2666 if (WIFEXITED(status
))
2667 rc
= WEXITSTATUS(status
);
2669 rc
|= 0x80; /* +128 to indicate sig */
2672 if (errno
!= EINTR
&& errno
!= ERESTART
)
2676 if (i
>= 10) /* repeated interrupts */
2683 letgo(private_t
*pri
)
2685 (void) printf("%s\t*** process otherwise traced, releasing ...\n",
2690 * Test for empty set.
2691 * support routine used by isemptyset() macro.
2694 is_empty(const uint32_t *sp
, /* pointer to set (array of int32's) */
2695 size_t n
) /* number of int32's in set */
2708 * OR the second set into the first.
2709 * The sets must be the same size.
2712 or_set(uint32_t *sp1
, const uint32_t *sp2
, size_t n
)