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_open
);
679 praddset(&traceeven
, SYS_vfork
);
680 praddset(&traceeven
, SYS_forksys
);
682 /* for I/O buffer dumps, force tracing of read()s and write()s */
683 if (!isemptyset(&readfd
)) {
684 praddset(&traceeven
, SYS_read
);
685 praddset(&traceeven
, SYS_readv
);
686 praddset(&traceeven
, SYS_pread
);
687 praddset(&traceeven
, SYS_recv
);
688 praddset(&traceeven
, SYS_recvfrom
);
689 praddset(&traceeven
, SYS_recvmsg
);
691 if (!isemptyset(&writefd
)) {
692 praddset(&traceeven
, SYS_write
);
693 praddset(&traceeven
, SYS_writev
);
694 praddset(&traceeven
, SYS_pwrite
);
695 praddset(&traceeven
, SYS_send
);
696 praddset(&traceeven
, SYS_sendto
);
697 praddset(&traceeven
, SYS_sendmsg
);
700 if (cflag
|| Eflag
) {
701 Psetsysentry(Proc
, &traceeven
);
703 Psetsysexit(Proc
, &traceeven
);
705 /* special case -- cannot trace sysexit because context is changed */
706 if (prismember(&trace
, SYS_context
)) {
707 (void) Psysentry(Proc
, SYS_context
, TRUE
);
708 (void) Psysexit(Proc
, SYS_context
, FALSE
);
709 prdelset(&traceeven
, SYS_context
);
712 /* special case -- trace exec() on entry to get the args */
713 (void) Psysentry(Proc
, SYS_execve
, TRUE
);
715 /* special case -- sysexit never reached */
716 (void) Psysentry(Proc
, SYS_exit
, TRUE
);
717 (void) Psysentry(Proc
, SYS_lwp_exit
, TRUE
);
718 (void) Psysexit(Proc
, SYS_exit
, FALSE
);
719 (void) Psysexit(Proc
, SYS_lwp_exit
, FALSE
);
721 Psetsignal(Proc
, &signals
); /* trace these signals */
722 Psetfault(Proc
, &faults
); /* trace these faults */
724 /* for function call tracing */
725 if (Dynpat
!= NULL
) {
726 /* trace these regardless, to deal with function calls */
727 (void) Pfault(Proc
, FLTBPT
, TRUE
);
728 (void) Pfault(Proc
, FLTTRACE
, TRUE
);
731 (void) Psetflags(Proc
, PR_BPTADJ
);
734 * Find functions and set breakpoints on grabbed process.
735 * A process stopped on exec() gets its breakpoints set below.
737 if ((Lsp
->pr_why
!= PR_SYSENTRY
&&
738 Lsp
->pr_why
!= PR_SYSEXIT
) ||
739 Lsp
->pr_what
!= SYS_execve
) {
740 establish_breakpoints();
746 * Use asynchronous-stop for multithreaded truss.
747 * truss runs one lwp for each lwp in the target process.
749 (void) Psetflags(Proc
, PR_ASYNC
);
751 /* flush out all tracing flags now. */
755 * If we grabbed a running process, set it running again.
756 * Since we are tracing lwp_create() and lwp_exit(), the
757 * lwps will not change in the process until we create all
758 * of the truss worker threads.
759 * We leave a created process stopped so its exec() can be reported.
761 first
= created
? FALSE
: TRUE
;
763 ((Pstate(Proc
) == PS_STOP
&& Lsp
->pr_why
== PR_REQUESTED
) ||
764 (Lsp
->pr_flags
& PR_DSTOP
)))
772 * Called from main() and from control() after fork().
775 main_thread(int first
)
777 private_t
*pri
= get_private();
785 * Block all signals in the main thread.
786 * Some worker thread will receive signals.
788 (void) thr_sigsetmask(SIG_SETMASK
, &fillset
, NULL
);
791 * If we are dealing with a previously hung process,
792 * arrange not to leave it hung on the same system call.
794 primary_lwp
= (first
&& Pstate(Proc
) == PS_STOP
)?
795 Pstatus(Proc
)->pr_lwp
.pr_lwpid
: 0;
798 * Create worker threads to match the lwps in the target process.
802 truss_lwpid
= my_realloc(truss_lwpid
, sizeof (lwpid_t
), NULL
);
805 (void) Plwp_iter(Proc
, create_thread
, &count
);
808 (void) printf("(Warning: no matching active LWPs found, "
814 * Set all of the truss worker threads running now.
816 (void) mutex_lock(&truss_lock
);
817 for (i
= 0; i
< truss_maxlwp
; i
++) {
819 (void) thr_continue(truss_lwpid
[i
]);
821 (void) mutex_unlock(&truss_lock
);
824 * Wait until all worker threads terminate.
826 while (thr_join(0, NULL
, NULL
) == 0)
829 (void) Punsetflags(Proc
, PR_ASYNC
);
833 flags
= PRELEASE_CLEAR
;
835 flags
|= PRELEASE_HANG
;
836 Prelease(Proc
, flags
);
839 retc
= (leave_hung
? 0 : wait4all());
842 interrupt
= 0; /* another interrupt kills the report */
846 report(pri
, times(&tms
) - starttime
);
848 } else if (cflag
&& fflag
) {
852 exit(retc
); /* exit with exit status of created process, else 0 */
856 worker_thread(void *arg
)
858 struct ps_lwphandle
*Lwp
= (struct ps_lwphandle
*)arg
;
859 const pstatus_t
*Psp
= Pstatus(Proc
);
860 const lwpstatus_t
*Lsp
= Lstatus(Lwp
);
861 struct syscount
*scp
;
862 lwpid_t who
= Lsp
->pr_lwpid
;
863 int first
= (who
== primary_lwp
);
864 private_t
*pri
= get_private();
866 int leave_it_hung
= FALSE
;
867 int reset_traps
= FALSE
;
870 int ow_in_effect
= 0;
873 char *ow_string
= NULL
;
875 sysset_t running_set
;
876 int dotrace
= lwptrace(Psp
->pr_pid
, Lsp
->pr_lwpid
);
880 pri
->syslast
= Lsp
->pr_stime
;
881 pri
->usrlast
= Lsp
->pr_utime
;
884 prfillset(&full_set
);
886 /* we were created with all signals blocked; unblock them */
887 (void) thr_sigsetmask(SIG_SETMASK
, &emptyset
, NULL
);
890 * Run this loop until the victim lwp terminates or we receive
891 * a termination condition (leave_hung | interrupt | sigusr1).
894 if (interrupt
| sigusr1
) {
895 (void) Lstop(Lwp
, MILLISEC
);
896 if (Lstate(Lwp
) == PS_RUN
)
899 if (Lstate(Lwp
) == PS_RUN
) {
900 /* millisecond timeout is for sleeping syscalls */
901 uint_t tout
= (iflag
|| req_flag
)? 0 : MILLISEC
;
904 * If we are to leave this lwp stopped in sympathy
905 * with another lwp that has been left hung, or if
906 * we have been interrupted or instructed to release
907 * our victim process, and this lwp is stopped but
908 * not on an event of interest to /proc, then just
909 * leave it in that state.
911 if ((leave_hung
| interrupt
| sigusr1
) &&
912 (Lsp
->pr_flags
& (PR_STOPPED
|PR_ISTOP
))
916 (void) Lwait(Lwp
, tout
);
917 if (Lstate(Lwp
) == PS_RUN
&&
918 tout
!= 0 && !(interrupt
| sigusr1
)) {
919 (void) mutex_lock(&truss_lock
);
920 if ((Lsp
->pr_flags
& PR_STOPPED
) &&
921 Lsp
->pr_why
== PR_JOBCONTROL
)
922 req_flag
= jobcontrol(pri
, dotrace
);
924 req_flag
= requested(pri
, req_flag
,
926 (void) mutex_unlock(&truss_lock
);
930 data_model
= Psp
->pr_dmodel
;
931 if (Lstate(Lwp
) == PS_UNDEAD
)
933 if (Lstate(Lwp
) == PS_LOST
) { /* we lost control */
935 * After exec(), only one LWP remains in the process.
936 * /proc makes the thread following that LWP receive
937 * EAGAIN (PS_LOST) if the program being exec()ed
938 * is a set-id program. Every other controlling
939 * thread receives ENOENT (because its LWP vanished).
940 * We are the controlling thread for the exec()ing LWP.
941 * We must wait until all of our siblings terminate
942 * before attempting to reopen the process.
944 (void) mutex_lock(&truss_lock
);
945 while (truss_nlwp
> 1)
946 (void) cond_wait(&truss_cv
, &truss_lock
);
947 if (Preopen(Proc
) == 0) { /* we got control back */
949 * We have to free and re-grab the LWP.
950 * The process is guaranteed to be at exit
951 * from exec() or execve() and have only
952 * one LWP, namely this one, and the LWP
953 * is guaranteed to have lwpid == 1.
954 * This "cannot fail".
959 Lgrab(Proc
, who
, &gcode
);
961 abend("Lgrab error: ",
963 pri
->lwpstat
= Lsp
= Lstatus(Lwp
);
964 (void) mutex_unlock(&truss_lock
);
968 /* we really lost it */
969 if (pri
->exec_string
&& *pri
->exec_string
) {
970 if (pri
->exec_pname
[0] != '\0')
971 (void) fputs(pri
->exec_pname
, stdout
);
973 (void) fputs(pri
->exec_string
, stdout
);
974 (void) fputc('\n', stdout
);
975 } else if (pri
->length
) {
976 (void) fputc('\n', stdout
);
980 "%s\t*** cannot trace across exec() of %s ***\n",
981 pri
->pname
, pri
->sys_path
);
984 "%s\t*** lost control of process ***\n",
988 (void) mutex_unlock(&truss_lock
);
991 if (Lstate(Lwp
) != PS_STOP
) {
992 (void) fprintf(stderr
,
993 "%s: state = %d\n", command
, Lstate(Lwp
));
994 abend(pri
->pname
, "uncaught status of subject lwp");
999 (void) mutex_lock(&truss_lock
);
1001 what
= Lsp
->pr_what
;
1004 switch (Lsp
->pr_why
) {
1008 req_flag
= signalled(pri
, req_flag
, dotrace
);
1009 if (Sflag
&& !first
&& prismember(&sighang
, what
))
1010 leave_it_hung
= TRUE
;
1013 if (what
== FLTBPT
) {
1016 (void) Pstop(Proc
, 0);
1017 rval
= function_trace(pri
, first
, 0, dotrace
);
1019 leave_it_hung
= TRUE
;
1023 if (faulted(pri
, dotrace
) &&
1024 Mflag
&& !first
&& prismember(&flthang
, what
))
1025 leave_it_hung
= TRUE
;
1027 case PR_JOBCONTROL
: /* can't happen except first time */
1028 req_flag
= jobcontrol(pri
, dotrace
);
1031 /* protect ourself from operating system error */
1032 if (what
<= 0 || what
> PRMAXSYS
)
1036 * ow_in_effect checks to see whether or not we
1037 * are attempting to quantify the time spent in
1038 * a one way system call. This is necessary as
1039 * some system calls never return, yet it is desireable
1040 * to determine how much time the traced process
1041 * spends in these calls. To do this, a one way
1042 * flag is set on SYSENTRY when the call is recieved.
1043 * After this, the call mask for the SYSENTRY events
1044 * is filled so that the traced process will stop
1045 * on the entry to the very next system call.
1046 * This appears to the the best way to determine
1047 * system time elapsed between a one way system call.
1048 * Once the next call occurs, values that have been
1049 * stashed are used to record the correct syscall
1050 * and time, and the SYSENTRY event mask is restored
1051 * so that the traced process may continue.
1053 if (dotrace
&& ow_in_effect
) {
1055 (void) mutex_lock(&count_lock
);
1056 scp
= Cp
->syscount
[ow_syscall
];
1057 if (ow_subcode
!= -1)
1060 accumulate(&scp
->stime
,
1061 &Lsp
->pr_stime
, &pri
->syslast
);
1062 accumulate(&Cp
->usrtotal
,
1063 &Lsp
->pr_utime
, &pri
->usrlast
);
1064 pri
->syslast
= Lsp
->pr_stime
;
1065 pri
->usrlast
= Lsp
->pr_utime
;
1066 (void) mutex_unlock(&count_lock
);
1070 (void) printf("%s\n", ow_string
);
1073 pri
->syslast
= Lsp
->pr_stime
;
1076 Psetsysentry(Proc
, &running_set
);
1080 * Special cases. Most syscalls are traced on exit.
1083 case SYS_exit
: /* exit() */
1084 case SYS_lwp_exit
: /* lwp_exit() */
1085 case SYS_context
: /* [get|set]context() */
1086 if (dotrace
&& cflag
&&
1087 prismember(&trace
, what
)) {
1090 ow_subcode
= getsubcode(pri
);
1091 pri
->syslast
= Lsp
->pr_stime
;
1093 (Pstatus(Proc
))->pr_sysentry
;
1094 Psetsysentry(Proc
, &full_set
);
1095 } else if (dotrace
&& Eflag
&&
1096 prismember(&trace
, what
)) {
1097 (void) sysentry(pri
, dotrace
);
1099 ow_string
= my_malloc(
1100 strlen(pri
->sys_string
) + 1, NULL
);
1101 (void) strcpy(ow_string
,
1104 (Pstatus(Proc
))->pr_sysentry
;
1105 Psetsysentry(Proc
, &full_set
);
1106 pri
->syslast
= Lsp
->pr_stime
;
1107 } else if (dotrace
&&
1108 prismember(&trace
, what
)) {
1109 (void) sysentry(pri
, dotrace
);
1113 printf("%s\n", pri
->sys_string
);
1117 *pri
->sys_string
= '\0';
1119 if (what
== SYS_exit
)
1123 show_cred(pri
, FALSE
, TRUE
);
1124 (void) sysentry(pri
, dotrace
);
1125 if (dotrace
&& !cflag
&&
1126 prismember(&trace
, what
)) {
1128 my_realloc(pri
->exec_string
,
1129 strlen(pri
->sys_string
) + 1,
1131 (void) strcpy(pri
->exec_pname
,
1133 (void) strcpy(pri
->exec_string
,
1135 pri
->length
+= strlen(pri
->sys_string
);
1136 pri
->exec_lwpid
= Lsp
->pr_lwpid
;
1139 *pri
->sys_string
= '\0';
1142 if (dotrace
&& (cflag
|| Eflag
) &&
1143 prismember(&trace
, what
)) {
1144 pri
->syslast
= Lsp
->pr_stime
;
1148 if (dotrace
&& Tflag
&& !first
&&
1149 (prismember(&syshang
, what
) ||
1150 (exit_called
&& prismember(&syshang
, SYS_exit
))))
1151 leave_it_hung
= TRUE
;
1154 /* check for write open of a /proc file */
1155 if (what
== SYS_openat
|| what
== SYS_open
) {
1158 (void) sysentry(pri
, dotrace
);
1159 pri
->Errno
= Lsp
->pr_errno
;
1160 pri
->ErrPriv
= Lsp
->pr_errpriv
;
1162 (what
== SYS_openat
&&
1163 pri
->sys_nargs
> 2 &&
1164 (pri
->sys_args
[2]&0x3) == O_RDONLY
) ||
1165 (what
== SYS_open
&&
1166 pri
->sys_nargs
> 1 &&
1167 (pri
->sys_args
[1]&0x3) == O_RDONLY
);
1168 if ((pri
->Errno
== 0 || pri
->Errno
== EBUSY
) &&
1169 pri
->sys_valid
&& !readonly
) {
1170 int rv
= checkproc(pri
);
1171 if (rv
== 1 && Fflag
!= PGRAB_FORCE
) {
1173 * The process opened itself
1174 * and no -F flag was specified.
1175 * Just print the open() call
1176 * and let go of the process.
1178 if (dotrace
&& !cflag
&&
1179 prismember(&trace
, what
)) {
1182 (void) printf("%s\n",
1187 (void) mutex_unlock(
1193 * Process opened someone else.
1194 * The open is being reissued.
1195 * Don't report this one.
1198 *pri
->sys_string
= '\0';
1204 if (what
== SYS_execve
&& pri
->Errno
== 0) {
1206 * Refresh the data model on exec() in case it
1207 * is different from the parent. Lwait()
1208 * doesn't update process-wide status, so we
1209 * have to explicitly call Pstopstatus() to get
1212 (void) Pstopstatus(Proc
, PCNULL
, 0);
1213 data_model
= Psp
->pr_dmodel
;
1215 if (sysexit(pri
, dotrace
))
1217 if (what
== SYS_lwp_create
&& pri
->Rval1
!= 0) {
1218 struct ps_lwphandle
*new_Lwp
;
1221 if ((new_Lwp
= grab_lwp(pri
->Rval1
)) != NULL
) {
1222 (void) thr_sigsetmask(SIG_SETMASK
,
1224 if (thr_create(NULL
, 0, worker_thread
,
1225 new_Lwp
, THR_BOUND
| THR_SUSPENDED
,
1227 abend("cannot create lwp ",
1228 "to follow child lwp");
1229 insert_lwpid(lwpid
);
1230 (void) thr_continue(lwpid
);
1231 (void) thr_sigsetmask(SIG_SETMASK
,
1236 if (dotrace
&& Tflag
&& !first
&&
1237 prismember(&syshang
, what
))
1238 leave_it_hung
= TRUE
;
1239 if (what
== SYS_execve
&& pri
->Errno
== 0) {
1240 is_vfork_child
= FALSE
;
1241 reset_breakpoints();
1243 * exec() resets the calling LWP's lwpid to 1.
1244 * If the LWP has changed its lwpid, then
1245 * we have to free and re-grab the LWP
1246 * in order to keep libproc consistent.
1247 * This "cannot fail".
1249 if (who
!= Lsp
->pr_lwpid
) {
1251 * We must wait for all of our
1252 * siblings to terminate.
1254 while (truss_nlwp
> 1)
1255 (void) cond_wait(&truss_cv
,
1257 who
= Lsp
->pr_lwpid
;
1260 Lgrab(Proc
, who
, &gcode
);
1262 abend("Lgrab error: ",
1263 Lgrab_error(gcode
));
1264 pri
->lwpstat
= Lsp
= Lstatus(Lwp
);
1270 (void) fprintf(stderr
,
1271 "unknown reason for stopping: %d/%d\n",
1276 if (pri
->child
) { /* controlled process fork()ed */
1277 if (fflag
|| Dynpat
!= NULL
) {
1278 if (Lsp
->pr_why
== PR_SYSEXIT
&&
1279 (Lsp
->pr_what
== SYS_vfork
||
1280 (Lsp
->pr_what
== SYS_forksys
&&
1281 Lsp
->pr_sysarg
[0] == 2))) {
1282 is_vfork_child
= TRUE
;
1283 (void) Pstop(Proc
, 0);
1285 if (control(pri
, pri
->child
)) {
1286 (void) mutex_unlock(&truss_lock
);
1290 * If this is vfork(), then
1291 * this clears the breakpoints
1292 * in the parent's address space
1293 * as well as in the child's.
1295 clear_breakpoints();
1296 Prelease(Proc
, PRELEASE_CLEAR
);
1304 * Here, we are still the parent truss.
1305 * If the child messes with the breakpoints and
1306 * this is vfork(), we have to set them again.
1308 if (Dynpat
!= NULL
&& is_vfork_child
&& !fflag
)
1310 is_vfork_child
= FALSE
;
1315 if (leave_it_hung
) {
1316 (void) mutex_unlock(&truss_lock
);
1322 * To recover from vfork, we must catch the lwp
1323 * that issued the vfork() when it returns to user
1324 * level, with all other lwps remaining stopped.
1325 * For this purpose, we have directed all lwps to
1326 * stop and we now set the vfork()ing lwp running
1327 * with the PRSTEP flag. We expect to capture it
1328 * when it stops again showing PR_FAULTED/FLTTRACE.
1329 * We are holding truss_lock, so no other threads
1330 * in truss will set any other lwps in the victim
1333 reset_traps
= FALSE
;
1334 (void) Lsetrun(Lwp
, 0, PRSTEP
);
1336 (void) Lwait(Lwp
, 0);
1337 } while (Lstate(Lwp
) == PS_RUN
);
1338 if (Lstate(Lwp
) == PS_STOP
&&
1339 Lsp
->pr_why
== PR_FAULTED
&&
1340 Lsp
->pr_what
== FLTTRACE
) {
1341 reestablish_traps();
1342 (void) Lsetrun(Lwp
, 0, PRCFAULT
|PRSTOP
);
1344 (void) printf("%s\t*** Expected PR_FAULTED/"
1345 "FLTTRACE stop following vfork()\n",
1350 if (Lstate(Lwp
) == PS_STOP
) {
1353 if (interrupt
| sigusr1
) {
1354 (void) mutex_unlock(&truss_lock
);
1358 * If we must leave this lwp hung is sympathy with
1359 * another lwp that is being left hung on purpose,
1360 * then push the state onward toward PR_REQUESTED.
1363 if (Lsp
->pr_why
== PR_REQUESTED
) {
1364 (void) mutex_unlock(&truss_lock
);
1369 if (Lsetrun(Lwp
, 0, flags
) != 0 &&
1370 Lstate(Lwp
) != PS_LOST
&&
1371 Lstate(Lwp
) != PS_UNDEAD
) {
1372 (void) mutex_unlock(&truss_lock
);
1374 abend("cannot start subject lwp", NULL
);
1380 (void) mutex_unlock(&truss_lock
);
1384 /* block all signals in preparation for exiting */
1385 (void) thr_sigsetmask(SIG_SETMASK
, &fillset
, NULL
);
1387 if (Lstate(Lwp
) == PS_UNDEAD
|| Lstate(Lwp
) == PS_LOST
)
1388 (void) mutex_lock(&truss_lock
);
1390 (void) Lstop(Lwp
, MILLISEC
);
1391 (void) mutex_lock(&truss_lock
);
1392 if (Lstate(Lwp
) == PS_STOP
&&
1393 Lsp
->pr_why
== PR_FAULTED
&&
1394 Lsp
->pr_what
== FLTBPT
)
1395 (void) function_trace(pri
, 0, 1, dotrace
);
1398 if (dotrace
&& ow_in_effect
) {
1400 (void) mutex_lock(&count_lock
);
1401 scp
= Cp
->syscount
[ow_syscall
];
1402 if (ow_subcode
!= -1)
1405 accumulate(&scp
->stime
,
1406 &Lsp
->pr_stime
, &pri
->syslast
);
1407 accumulate(&Cp
->usrtotal
,
1408 &Lsp
->pr_utime
, &pri
->usrlast
);
1409 pri
->syslast
= Lsp
->pr_stime
;
1410 pri
->usrlast
= Lsp
->pr_utime
;
1411 (void) mutex_unlock(&count_lock
);
1415 (void) printf("%s\n", ow_string
);
1418 pri
->syslast
= Lsp
->pr_stime
;
1421 Psetsysentry(Proc
, &running_set
);
1424 if (Lstate(Lwp
) == PS_UNDEAD
|| Lstate(Lwp
) == PS_LOST
) {
1426 * The victim thread has exited or we lost control of
1427 * the process. Remove ourself from the list of all
1428 * truss threads and notify everyone waiting for this.
1430 lwpid_t my_id
= thr_self();
1433 for (i
= 0; i
< truss_maxlwp
; i
++) {
1434 if (truss_lwpid
[i
] == my_id
) {
1439 if (--truss_nlwp
!= 0) {
1440 (void) cond_broadcast(&truss_cv
);
1443 * The last truss worker thread is terminating.
1444 * The address space is gone (UNDEAD) or is
1445 * inaccessible (LOST) so we cannot clear the
1446 * breakpoints. Just report the htable stats.
1448 report_htable_stats();
1452 * The victim thread is not a zombie thread, and we have not
1453 * lost control of the process. We must have gotten here due
1454 * to (leave_hung || leave_it_hung || interrupt || sigusr1).
1455 * In these cases, we must carefully uninstrument the process
1456 * and either set it running or leave it stopped and abandoned.
1458 static int nstopped
= 0;
1459 static int cleared
= 0;
1463 if ((leave_hung
| interrupt
| sigusr1
) == 0)
1464 abend("(leave_hung | interrupt | sigusr1) == 0", NULL
);
1467 * The first truss thread through here needs to instruct all
1468 * application threads to stop -- they're not necessarily
1469 * going to stop on their own.
1471 if (nstopped
++ == 0)
1472 (void) Pdstop(Proc
);
1475 * Notify all other worker threads about the reason
1476 * for being here (leave_hung || interrupt || sigusr1).
1478 broadcast_signals();
1481 * Once the last thread has reached this point, then and
1482 * only then is it safe to remove breakpoints and other
1483 * instrumentation. Since breakpoints are executed without
1484 * truss_lock held, a monitor thread can't exit until all
1485 * breakpoints have been removed, and we can't be sure the
1486 * procedure to execute a breakpoint won't temporarily
1487 * reinstall a breakpont. Accordingly, we need to wait
1488 * until all threads are in a known state.
1490 while (nstopped
!= truss_nlwp
)
1491 (void) cond_wait(&truss_cv
, &truss_lock
);
1494 * All truss threads have reached this point.
1495 * One of them clears the breakpoints and
1496 * wakes up everybody else to finish up.
1498 if (cleared
++ == 0) {
1500 * All threads should already be stopped,
1501 * but just to be safe...
1503 (void) Pstop(Proc
, MILLISEC
);
1504 clear_breakpoints();
1505 (void) Psysexit(Proc
, SYS_vfork
, FALSE
);
1506 (void) Psysexit(Proc
, SYS_forksys
, FALSE
);
1507 (void) Punsetflags(Proc
, PR_FORK
);
1510 (void) cond_broadcast(&truss_cv
);
1513 if (!leave_hung
&& Lstate(Lwp
) == PS_STOP
)
1514 (void) Lsetrun(Lwp
, 0, 0);
1518 (void) mutex_unlock(&truss_lock
);
1523 * Give a base date for time stamps, adjusted to the
1524 * stop time of the selected (first or created) process.
1527 setup_basetime(hrtime_t basehrtime
, struct timeval
*basedate
)
1529 const pstatus_t
*Psp
= Pstatus(Proc
);
1530 (void) mutex_lock(&count_lock
);
1531 Cp
->basetime
= Psp
->pr_lwp
.pr_tstamp
;
1532 (void) mutex_unlock(&count_lock
);
1534 if ((dflag
|Dflag
) && !cflag
) {
1535 const struct tm
*ptm
;
1538 hrtime_t delta
= basehrtime
-
1539 ((hrtime_t
)Cp
->basetime
.tv_sec
* NANOSEC
+
1540 Cp
->basetime
.tv_nsec
);
1543 basedate
->tv_sec
-= (time_t)(delta
/ NANOSEC
);
1544 basedate
->tv_usec
-= (delta
% NANOSEC
) / 1000;
1545 if (basedate
->tv_usec
< 0) {
1547 basedate
->tv_usec
+= MICROSEC
;
1550 ptm
= localtime(&basedate
->tv_sec
);
1551 ptime
= asctime(ptm
);
1552 if ((pdst
= tzname
[ptm
->tm_isdst
? 1 : 0]) == NULL
)
1556 "Base time stamp: %ld.%4.4ld [ %.20s%s %.4s ]\n",
1557 basedate
->tv_sec
, basedate
->tv_usec
/ 100,
1558 ptime
, pdst
, ptime
+ 20);
1565 * Performs per-process initializations. If truss is following a victim
1566 * process it will fork additional truss processes to follow new processes
1567 * created. Here is where each new truss process gets its per-process data
1575 struct timeval basedate
;
1576 hrtime_t basehrtime
;
1577 struct syscount
*scp
;
1579 timestruc_t c_basetime
;
1581 /* Make sure we only configure the basetime for the first truss proc */
1584 pmem
= my_malloc(sizeof (struct counts
) + maxsyscalls() *
1585 sizeof (struct syscount
), NULL
);
1586 Cp
= (struct counts
*)pmem
;
1587 basehrtime
= gethrtime();
1588 (void) gettimeofday(&basedate
, NULL
);
1589 setup_basetime(basehrtime
, &basedate
);
1592 c_basetime
= Cp
->basetime
;
1594 (void) memset(Cp
, 0, sizeof (struct counts
) + maxsyscalls() *
1595 sizeof (struct syscount
));
1597 Cp
->basetime
= c_basetime
;
1599 if (fcall_tbl
!= NULL
)
1600 destroy_hash(fcall_tbl
);
1601 fcall_tbl
= init_hash(4096);
1603 (void) mutex_lock(&count_lock
);
1604 scp
= (struct syscount
*)(Cp
+ 1);
1605 for (i
= 0; i
<= PRMAXSYS
; i
++) {
1606 Cp
->syscount
[i
] = scp
;
1607 scp
+= nsubcodes(i
);
1609 (void) mutex_unlock(&count_lock
);
1614 * Writes child state to a tempfile where it can be read and
1615 * accumulated by the parent process. The file descriptor is shared
1616 * among the processes. Ordering of writes does not matter, it is, however,
1617 * necessary to ensure that all writes are atomic.
1628 unsigned char *buf
= NULL
;
1633 /* ensure that we are in fact a child process */
1637 /* enumerate fcall_tbl (tbl locked until freed) */
1638 if (Dynpat
!= NULL
) {
1639 itr
= iterate_hash(fcall_tbl
);
1641 ntry
= iter_next(itr
);
1642 while (ntry
!= NULL
) {
1643 fentry
.type
= HD_hashntry
;
1644 fentry
.count
= ntry
->count
;
1651 if (i
+ sizeof (fentry
) > bufsz
) {
1652 buf
= my_realloc(buf
, i
+ j
+ sizeof (fentry
),
1654 bufsz
= i
+ j
+ sizeof (fentry
);
1656 (void) memcpy(buf
, &fentry
, sizeof (fentry
));
1657 (void) strlcpy((char *)(buf
+ sizeof (fentry
)), t
, j
);
1658 (void) strlcpy((char *)(buf
+ sizeof (fentry
) + j
),
1660 if (write(sfd
, buf
, sizeof (fentry
) + i
+ j
) == -1)
1661 abend("Error writing to tmp file", NULL
);
1662 ntry
= iter_next(itr
);
1667 /* Now write the count/syscount structs down */
1668 bufsz
= sizeof (fentry
) + (sizeof (struct counts
) + maxsyscalls() *
1669 sizeof (struct syscount
));
1670 buf
= my_realloc(buf
, bufsz
, NULL
);
1671 fentry
.type
= HD_cts_syscts
;
1672 fentry
.count
= 0; /* undefined, really */
1673 fentry
.sz_key
= bufsz
- sizeof (fentry
);
1674 fentry
.sz_lib
= 0; /* also undefined */
1675 (void) memcpy(buf
, &fentry
, sizeof (fentry
));
1676 (void) memcpy((char *)(buf
+ sizeof (fentry
)), Cp
,
1677 bufsz
- sizeof (fentry
));
1678 if (write(sfd
, buf
, bufsz
) == -1)
1679 abend("Error writing cts/syscts to tmpfile", NULL
);
1685 * The following reads entries from the tempfile back to the parent
1686 * so that information can be collected and summed for overall statistics.
1687 * This reads records out of the tempfile. If they are hash table entries,
1688 * the record is merged with the hash table kept by the parent process.
1689 * If the information is a struct count/struct syscount pair, they are
1690 * copied and added into the count/syscount array kept by the parent.
1699 size_t c_offset
= 0;
1708 if (fstat(sfd
, &fsi
) == -1)
1709 abend("Error stat-ing tempfile", NULL
);
1710 filesz
= fsi
.st_size
;
1712 while (c_offset
< filesz
) {
1713 /* first get hdntry */
1714 if (pread(sfd
, &ntry
, sizeof (hdntry_t
), c_offset
) !=
1716 abend("Unable to perform full read of hdntry", NULL
);
1717 c_offset
+= sizeof (hdntry_t
);
1719 switch (ntry
.type
) {
1722 /* first get lib string */
1723 if (ntry
.sz_lib
> t_strsz
) {
1724 t
= my_realloc(t
, ntry
.sz_lib
, NULL
);
1725 t_strsz
= ntry
.sz_lib
;
1728 (void) memset(t
, 0, t_strsz
);
1730 /* now actually get the string */
1731 if (pread(sfd
, t
, ntry
.sz_lib
, c_offset
) != ntry
.sz_lib
)
1732 abend("Unable to perform full read of lib str",
1734 c_offset
+= ntry
.sz_lib
;
1736 /* now get key string */
1738 if (ntry
.sz_key
> s_strsz
) {
1739 s
= my_realloc(s
, ntry
.sz_key
, NULL
);
1740 s_strsz
= ntry
.sz_key
;
1742 (void) memset(s
, 0, s_strsz
);
1743 if (pread(sfd
, s
, ntry
.sz_key
, c_offset
) != ntry
.sz_key
)
1744 abend("Unable to perform full read of key str",
1746 c_offset
+= ntry
.sz_key
;
1748 add_fcall(fcall_tbl
, t
, s
, ntry
.count
);
1754 size_t bfsz
= sizeof (struct counts
) + maxsyscalls()
1755 * sizeof (struct syscount
);
1757 struct syscount
*sscp
;
1759 if (ntry
.sz_key
!= bfsz
)
1760 abend("cts/syscts size does not sanity check",
1762 ncp
= my_malloc(ntry
.sz_key
, NULL
);
1764 if (pread(sfd
, ncp
, ntry
.sz_key
, c_offset
) !=
1766 abend("Unable to perform full read of cts",
1768 c_offset
+= ntry
.sz_key
;
1770 sscp
= (struct syscount
*)(ncp
+ 1);
1772 (void) mutex_lock(&count_lock
);
1774 Cp
->usrtotal
.tv_sec
+= ncp
->usrtotal
.tv_sec
;
1775 Cp
->usrtotal
.tv_nsec
+= ncp
->usrtotal
.tv_nsec
;
1776 if (Cp
->usrtotal
.tv_nsec
>= NANOSEC
) {
1777 Cp
->usrtotal
.tv_nsec
-= NANOSEC
;
1778 Cp
->usrtotal
.tv_sec
++;
1780 for (i
= 0; i
<= PRMAXSYS
; i
++) {
1781 ncp
->syscount
[i
] = sscp
;
1782 sscp
+= nsubcodes(i
);
1785 for (i
= 0; i
<= PRMAXFAULT
; i
++) {
1786 Cp
->fltcount
[i
] += ncp
->fltcount
[i
];
1789 for (i
= 0; i
<= PRMAXSIG
; i
++) {
1790 Cp
->sigcount
[i
] += ncp
->sigcount
[i
];
1793 for (i
= 0; i
<= PRMAXSYS
; i
++) {
1794 struct syscount
*scp
= Cp
->syscount
[i
];
1795 struct syscount
*nscp
= ncp
->syscount
[i
];
1796 int n
= nsubcodes(i
);
1799 for (subcode
= 0; subcode
< n
; subcode
++,
1801 scp
->count
+= nscp
->count
;
1802 scp
->error
+= nscp
->error
;
1803 scp
->stime
.tv_sec
+= nscp
->stime
.tv_sec
;
1804 scp
->stime
.tv_nsec
+=
1805 nscp
->stime
.tv_nsec
;
1806 if (scp
->stime
.tv_nsec
>= NANOSEC
) {
1807 scp
->stime
.tv_nsec
-= NANOSEC
;
1808 scp
->stime
.tv_sec
++;
1812 (void) mutex_unlock(&count_lock
);
1818 abend("Unknown file entry type encountered", NULL
);
1823 if (fstat(sfd
, &fsi
) == -1)
1824 abend("Error stat-ing tempfile", NULL
);
1825 filesz
= fsi
.st_size
;
1832 make_pname(private_t
*pri
, id_t tid
)
1835 int ff
= (fflag
|| ngrab
> 1);
1836 int lf
= (lflag
| tid
| (Thr_agent
!= NULL
) | (truss_nlwp
> 1));
1837 pid_t pid
= Pstatus(Proc
)->pr_pid
;
1838 id_t lwpid
= pri
->lwpstat
->pr_lwpid
;
1840 if (ff
!= pri
->pparam
.ff
||
1841 lf
!= pri
->pparam
.lf
||
1842 pid
!= pri
->pparam
.pid
||
1843 lwpid
!= pri
->pparam
.lwpid
||
1844 tid
!= pri
->pparam
.tid
) {
1845 char *s
= pri
->pname
;
1848 s
+= sprintf(s
, "%d", (int)pid
);
1850 s
+= sprintf(s
, "/%d", (int)lwpid
);
1852 s
+= sprintf(s
, "@%d", (int)tid
);
1854 *s
++ = ':', *s
++ = '\t';
1855 if (ff
&& lf
&& s
< pri
->pname
+ 9)
1858 pri
->pparam
.ff
= ff
;
1859 pri
->pparam
.lf
= lf
;
1860 pri
->pparam
.pid
= pid
;
1861 pri
->pparam
.lwpid
= lwpid
;
1862 pri
->pparam
.tid
= tid
;
1868 * Print the pri->pname[] string, if any.
1871 putpname(private_t
*pri
)
1874 (void) fputs(pri
->pname
, stdout
);
1878 * Print the timestamp, if requested (-d, -D, or -E).
1881 timestamp(private_t
*pri
)
1883 const lwpstatus_t
*Lsp
= pri
->lwpstat
;
1887 if (!(dflag
|Dflag
|Eflag
) || !(Lsp
->pr_flags
& PR_STOPPED
))
1890 seconds
= Lsp
->pr_tstamp
.tv_sec
- Cp
->basetime
.tv_sec
;
1891 fraction
= Lsp
->pr_tstamp
.tv_nsec
- Cp
->basetime
.tv_nsec
;
1894 fraction
+= NANOSEC
;
1896 /* fraction in 1/10 milliseconds, rounded up */
1897 fraction
= (fraction
+ 50000) / 100000;
1898 if (fraction
>= (MILLISEC
* 10)) {
1900 fraction
-= (MILLISEC
* 10);
1903 if (dflag
) /* time stamp */
1904 (void) printf("%2d.%4.4d\t", seconds
, fraction
);
1906 if (Dflag
) { /* time delta */
1907 int oseconds
= pri
->seconds
;
1908 int ofraction
= pri
->fraction
;
1910 pri
->seconds
= seconds
;
1911 pri
->fraction
= fraction
;
1912 seconds
-= oseconds
;
1913 fraction
-= ofraction
;
1916 fraction
+= (MILLISEC
* 10);
1918 (void) printf("%2d.%4.4d\t", seconds
, fraction
);
1922 seconds
= Lsp
->pr_stime
.tv_sec
- pri
->syslast
.tv_sec
;
1923 fraction
= Lsp
->pr_stime
.tv_nsec
- pri
->syslast
.tv_nsec
;
1927 fraction
+= NANOSEC
;
1929 /* fraction in 1/10 milliseconds, rounded up */
1930 fraction
= (fraction
+ 50000) / 100000;
1931 if (fraction
>= (MILLISEC
* 10)) {
1933 fraction
-= (MILLISEC
* 10);
1935 (void) printf("%2d.%4.4d\t", seconds
, fraction
);
1940 * Create output file, being careful about
1941 * suid/sgid and file descriptor 0, 1, 2 issues.
1949 if (Euid
== Ruid
&& Egid
== Rgid
) /* not set-id */
1950 fd
= creat(path
, mode
);
1951 else if (access(path
, F_OK
) != 0) { /* file doesn't exist */
1952 /* if directory permissions OK, create file & set ownership */
1958 /* generate path for directory containing file */
1959 if ((p
= strrchr(path
, '/')) == NULL
) { /* no '/' */
1961 *p
++ = '.'; /* current directory */
1963 } else if (p
== path
) { /* leading '/' */
1965 *p
++ = '/'; /* root directory */
1967 } else { /* embedded '/' */
1968 dir
= path
; /* directory path */
1972 if (access(dir
, W_OK
|X_OK
) != 0) {
1973 /* not writeable/searchable */
1976 } else { /* create file and set ownership correctly */
1978 if ((fd
= creat(path
, mode
)) >= 0)
1979 (void) chown(path
, (int)Ruid
, (int)Rgid
);
1981 } else if (access(path
, W_OK
) != 0) /* file not writeable */
1984 fd
= creat(path
, mode
);
1987 * Make sure it's not one of 0, 1, or 2.
1988 * This allows truss to work when spawned by init(1m).
1990 if (0 <= fd
&& fd
<= 2) {
1991 int dfd
= fcntl(fd
, F_DUPFD
, 3);
1997 * Mark it close-on-exec so created processes don't inherit it.
2000 (void) fcntl(fd
, F_SETFD
, FD_CLOEXEC
);
2010 (void) fcntl(2, F_DUPFD
, 1);
2011 } else if (ofd
!= 1) {
2013 (void) fcntl(ofd
, F_DUPFD
, 1);
2015 /* if no stderr, make it the same file */
2016 if ((ofd
= dup(2)) < 0)
2017 (void) fcntl(1, F_DUPFD
, 2);
2024 * Accumulate time differencies: a += e - s;
2027 accumulate(timestruc_t
*ap
, const timestruc_t
*ep
, const timestruc_t
*sp
)
2029 ap
->tv_sec
+= ep
->tv_sec
- sp
->tv_sec
;
2030 ap
->tv_nsec
+= ep
->tv_nsec
- sp
->tv_nsec
;
2031 if (ap
->tv_nsec
>= NANOSEC
) {
2032 ap
->tv_nsec
-= NANOSEC
;
2034 } else if (ap
->tv_nsec
< 0) {
2035 ap
->tv_nsec
+= NANOSEC
;
2041 lib_sort(const void *p1
, const void *p2
)
2047 hentry_t
*t1
= (hentry_t
*)p1
;
2048 hentry_t
*t2
= (hentry_t
*)p2
;
2053 if ((cmpr
= strcmp(p
, q
)) == 0) {
2063 return (strcmp(p
, q
));
2070 report(private_t
*pri
, time_t lapse
) /* elapsed time, clock ticks */
2078 timestruc_t tickzero
;
2080 timestruc_t ticktot
;
2085 for (i
= 0, total
= 0; i
<= PRMAXFAULT
&& !interrupt
; i
++) {
2086 if ((count
= Cp
->fltcount
[i
]) != 0) {
2087 if (total
== 0) /* produce header */
2088 (void) printf("faults -------------\n");
2090 name
= proc_fltname(i
, pri
->flt_name
,
2091 sizeof (pri
->flt_name
));
2093 (void) printf("%s%s\t%4ld\n", name
,
2094 (((int)strlen(name
) < 8)?
2095 (const char *)"\t" : (const char *)""),
2100 if (total
&& !interrupt
)
2101 (void) printf("total:\t\t%4ld\n\n", total
);
2103 for (i
= 0, total
= 0; i
<= PRMAXSIG
&& !interrupt
; i
++) {
2104 if ((count
= Cp
->sigcount
[i
]) != 0) {
2105 if (total
== 0) /* produce header */
2106 (void) printf("signals ------------\n");
2107 name
= signame(pri
, i
);
2108 (void) printf("%s%s\t%4ld\n", name
,
2109 (((int)strlen(name
) < 8)?
2110 (const char *)"\t" : (const char *)""),
2115 if (total
&& !interrupt
)
2116 (void) printf("total:\t\t%4ld\n\n", total
);
2118 if ((Dynpat
!= NULL
) && !interrupt
) {
2119 size_t elem
= elements_in_table(fcall_tbl
);
2120 hiter_t
*itr
= iterate_hash(fcall_tbl
);
2121 hentry_t
*tmp
= iter_next(itr
);
2122 hentry_t
*stbl
= my_malloc(elem
* sizeof (hentry_t
), NULL
);
2124 while ((tmp
!= NULL
) && (i
< elem
)) {
2125 stbl
[i
].prev
= tmp
->prev
;
2126 stbl
[i
].next
= tmp
->next
;
2127 stbl
[i
].lib
= tmp
->lib
;
2128 stbl
[i
].key
= tmp
->key
;
2129 stbl
[i
].count
= tmp
->count
;
2130 tmp
= iter_next(itr
);
2133 qsort((void *)stbl
, elem
, sizeof (hentry_t
),
2136 "\n%-20s %-40s %s\n", "Library:", "Function", "calls");
2137 for (i
= 0; i
< elem
; i
++) {
2138 (void) printf("%-20s %-40s %ld\n", stbl
[i
].lib
,
2139 stbl
[i
].key
, stbl
[i
].count
);
2148 "\nsyscall seconds calls errors\n");
2151 tickzero
.tv_sec
= ticks
.tv_sec
= ticktot
.tv_sec
= 0;
2152 tickzero
.tv_nsec
= ticks
.tv_nsec
= ticktot
.tv_nsec
= 0;
2153 for (i
= 0; i
<= PRMAXSYS
&& !interrupt
; i
++) {
2154 struct syscount
*scp
= Cp
->syscount
[i
];
2155 int n
= nsubcodes(i
);
2158 for (subcode
= 0; subcode
< n
; subcode
++, scp
++) {
2159 if ((count
= scp
->count
) != 0 || scp
->error
) {
2160 (void) printf("%-19.19s ",
2161 sysname(pri
, i
, subcode
));
2164 accumulate(&ticktot
, &ticks
, &tickzero
);
2167 (void) printf(" %7ld", count
);
2168 if ((error
= scp
->error
) != 0)
2169 (void) printf(" %7ld", error
);
2170 (void) fputc('\n', stdout
);
2179 " -------- ------ ----\n");
2180 (void) printf("sys totals: ");
2182 (void) printf(" %7ld %6ld\n", total
, errtot
);
2186 (void) printf("usr time: ");
2187 prtim(&Cp
->usrtotal
);
2188 (void) fputc('\n', stdout
);
2192 int hz
= (int)sysconf(_SC_CLK_TCK
);
2194 ticks
.tv_sec
= lapse
/ hz
;
2195 ticks
.tv_nsec
= (lapse
% hz
) * (1000000000 / hz
);
2196 (void) printf("elapsed: ");
2198 (void) fputc('\n', stdout
);
2203 prtim(timestruc_t
*tp
)
2207 if ((sec
= tp
->tv_sec
) != 0) /* whole seconds */
2208 (void) printf("%5lu", sec
);
2212 (void) printf(".%3.3ld", tp
->tv_nsec
/1000000); /* fraction */
2216 * Gather process id's.
2217 * Return 0 on success, != 0 on failure.
2220 pids(char *arg
, proc_set_t
*grab
)
2224 const char *lwps
= NULL
;
2226 if ((pid
= proc_arg_xpsinfo(arg
, PR_ARG_PIDS
, NULL
, &i
, &lwps
)) < 0) {
2227 (void) fprintf(stderr
, "%s: cannot trace '%s': %s\n",
2228 command
, arg
, Pgrab_error(i
));
2232 for (i
= 0; i
< ngrab
; i
++)
2233 if (grab
[i
].pid
== pid
) /* duplicate */
2237 grab
[ngrab
].pid
= pid
;
2238 grab
[ngrab
].lwps
= lwps
;
2241 (void) fprintf(stderr
, "%s: duplicate process-id ignored: %d\n",
2247 * Report psargs string.
2250 psargs(private_t
*pri
)
2252 pid_t pid
= Pstatus(Proc
)->pr_pid
;
2255 if (proc_get_psinfo(pid
, &psinfo
) == 0)
2256 (void) printf("%spsargs: %.64s\n",
2257 pri
->pname
, psinfo
.pr_psargs
);
2260 (void) printf("%s\t*** Cannot read psinfo file for pid %d\n",
2261 pri
->pname
, (int)pid
);
2266 fetchstring(private_t
*pri
, long addr
, int maxleng
)
2273 if (pri
->str_bsize
== 0) /* initial allocation of string buffer */
2275 my_malloc(pri
->str_bsize
= 16, "string buffer");
2276 *pri
->str_buffer
= '\0';
2278 for (nbyte
= 40; nbyte
== 40 && leng
< maxleng
; addr
+= 40) {
2279 if ((nbyte
= Pread(Proc
, string
, 40, addr
)) <= 0)
2280 return (leng
? pri
->str_buffer
: NULL
);
2282 (nbyte
= strlen(string
)) > 0) {
2283 while (leng
+ nbyte
>= pri
->str_bsize
)
2285 my_realloc(pri
->str_buffer
,
2286 pri
->str_bsize
*= 2, "string buffer");
2287 (void) strcpy(pri
->str_buffer
+leng
, string
);
2294 pri
->str_buffer
[leng
] = '\0';
2296 return (pri
->str_buffer
);
2300 getset(prpriv_t
*p
, priv_ptype_t set
)
2302 return ((priv_set_t
*)
2303 &p
->pr_sets
[priv_getsetbyname(set
) * p
->pr_setsize
]);
2307 show_cred(private_t
*pri
, int new, int loadonly
)
2312 if (proc_get_cred(Pstatus(Proc
)->pr_pid
, &cred
, 0) < 0) {
2313 perror("show_cred() - credential");
2314 (void) printf("%s\t*** Cannot get credentials\n", pri
->pname
);
2317 if ((privs
= proc_get_priv(Pstatus(Proc
)->pr_pid
)) == NULL
) {
2318 perror("show_cred() - privileges");
2319 (void) printf("%s\t*** Cannot get privileges\n", pri
->pname
);
2323 if (!loadonly
&& !cflag
&& prismember(&trace
, SYS_execve
)) {
2326 if ((new && cred
.pr_ruid
!= cred
.pr_suid
) ||
2327 cred
.pr_ruid
!= credentials
.pr_ruid
||
2328 cred
.pr_suid
!= credentials
.pr_suid
)
2330 "%s *** SUID: ruid/euid/suid = %d / %d / %d ***\n",
2335 if ((new && cred
.pr_rgid
!= cred
.pr_sgid
) ||
2336 cred
.pr_rgid
!= credentials
.pr_rgid
||
2337 cred
.pr_sgid
!= credentials
.pr_sgid
)
2339 "%s *** SGID: rgid/egid/sgid = %d / %d / %d ***\n",
2344 if (privdata
!= NULL
&& cred
.pr_euid
!= 0) {
2345 priv_set_t
*npset
= getset(privs
, PRIV_PERMITTED
);
2346 priv_set_t
*opset
= getset(privdata
, PRIV_PERMITTED
);
2348 if (!priv_issubset(npset
, opset
)) {
2349 /* Use the to be freed privdata as scratch */
2350 priv_inverse(opset
);
2351 priv_intersect(npset
, opset
);
2352 s
= priv_set_to_str(opset
, ',', PRIV_STR_SHORT
);
2353 t
= priv_set_to_str(npset
, ',', PRIV_STR_SHORT
);
2354 (void) printf("%s *** FPRIV: P/E: %s ***\n",
2356 strlen(s
) > strlen(t
) ? t
: s
);
2363 proc_free_priv(privdata
);
2369 * Take control of a child process.
2370 * We come here with truss_lock held.
2373 control(private_t
*pri
, pid_t pid
)
2375 const pstatus_t
*Psp
;
2376 const lwpstatus_t
*Lsp
;
2381 (void) mutex_lock(&gps
->fork_lock
);
2382 while (gps
->fork_pid
!= 0)
2383 (void) cond_wait(&gps
->fork_cv
, &gps
->fork_lock
);
2384 gps
->fork_pid
= getpid(); /* parent pid */
2385 if ((childpid
= fork()) == -1) {
2386 (void) printf("%s\t*** Cannot fork() to control process #%d\n",
2387 pri
->pname
, (int)pid
);
2390 (void) cond_broadcast(&gps
->fork_cv
);
2391 (void) mutex_unlock(&gps
->fork_lock
);
2396 if (childpid
!= 0) {
2398 * The parent carries on, after a brief pause.
2399 * The parent must wait until the child executes procadd(pid).
2401 while (gps
->fork_pid
!= childpid
)
2402 (void) cond_wait(&gps
->fork_cv
, &gps
->fork_lock
);
2404 (void) cond_broadcast(&gps
->fork_cv
);
2405 (void) mutex_unlock(&gps
->fork_lock
);
2409 childpid
= getpid();
2411 exit_called
= FALSE
;
2412 Pfree(Proc
); /* forget old process */
2415 * The parent process owns the shared gps->fork_lock.
2416 * The child must grab it again.
2418 (void) mutex_lock(&gps
->fork_lock
);
2421 * Child grabs the process and retains the tracing flags.
2423 if ((Proc
= Pgrab(pid
, PGRAB_RETAIN
, &rc
)) == NULL
) {
2424 (void) fprintf(stderr
,
2425 "%s: cannot control child process, pid# %d: %s\n",
2426 command
, (int)pid
, Pgrab_error(rc
));
2427 gps
->fork_pid
= childpid
;
2428 (void) cond_broadcast(&gps
->fork_cv
);
2429 (void) mutex_unlock(&gps
->fork_lock
);
2435 * Add ourself to the set of truss processes
2436 * and notify the parent to carry on.
2439 gps
->fork_pid
= childpid
;
2440 (void) cond_broadcast(&gps
->fork_cv
);
2441 (void) mutex_unlock(&gps
->fork_lock
);
2444 * We may have grabbed the child before it is fully stopped on exit
2445 * from fork. Wait one second (at most) for it to settle down.
2447 (void) Pwait(Proc
, MILLISEC
);
2448 if (Rdb_agent
!= NULL
)
2449 Rdb_agent
= Prd_agent(Proc
);
2451 Psp
= Pstatus(Proc
);
2454 data_model
= Psp
->pr_dmodel
;
2458 pri
->syslast
= Psp
->pr_stime
;
2459 pri
->usrlast
= Psp
->pr_utime
;
2461 flags
= PR_FORK
| PR_ASYNC
;
2463 flags
|= PR_BPTADJ
; /* needed for x86 */
2464 (void) Psetflags(Proc
, flags
);
2470 * Take control of an existing process.
2473 grabit(private_t
*pri
, proc_set_t
*set
)
2475 const pstatus_t
*Psp
;
2476 const lwpstatus_t
*Lsp
;
2480 * Don't force the takeover unless the -F option was specified.
2482 if ((Proc
= Pgrab(set
->pid
, Fflag
, &gcode
)) == NULL
) {
2483 (void) fprintf(stderr
, "%s: %s: %d\n",
2484 command
, Pgrab_error(gcode
), (int)set
->pid
);
2485 pri
->lwpstat
= NULL
;
2488 Psp
= Pstatus(Proc
);
2494 data_model
= Psp
->pr_dmodel
;
2495 pri
->syslast
= Psp
->pr_stime
;
2496 pri
->usrlast
= Psp
->pr_utime
;
2498 if (fflag
|| Dynpat
!= NULL
)
2499 (void) Psetflags(Proc
, PR_FORK
);
2501 (void) Punsetflags(Proc
, PR_FORK
);
2502 procadd(set
->pid
, set
->lwps
);
2503 show_cred(pri
, TRUE
, FALSE
);
2508 * Release process from control.
2511 release(private_t
*pri
, pid_t pid
)
2514 * The process in question is the child of a traced process.
2515 * We are here to turn off the inherited tracing flags.
2524 /* process is freshly forked, no need for exclusive open */
2525 (void) sprintf(ctlname
, "/proc/%d/ctl", (int)pid
);
2526 if ((fd
= open(ctlname
, O_WRONLY
)) < 0 ||
2527 write(fd
, (char *)ctl
, sizeof (ctl
)) < 0) {
2528 perror("release()");
2530 "%s\t*** Cannot release child process, pid# %d\n",
2531 pri
->pname
, (int)pid
);
2534 if (fd
>= 0) /* run-on-last-close sets the process running */
2542 * SIGUSR1 is special. It is used by one truss process to tell
2543 * another truss process to release its controlled process.
2544 * SIGUSR2 is also special. It is used to wake up threads waiting
2545 * for a victim lwp to stop after an event that will leave the
2546 * process hung (stopped and abandoned) has occurred.
2548 if (sig
== SIGUSR1
) {
2550 } else if (sig
== SIGUSR2
) {
2553 struct ps_lwphandle
*Lwp
;
2555 if (thr_getspecific(private_key
, &value
) == 0 &&
2556 (pri
= value
) != NULL
&&
2557 (Lwp
= pri
->Lwp
) != NULL
)
2558 (void) Lstop(Lwp
, MILLISEC
/ 10);
2565 errmsg(const char *s
, const char *q
)
2572 (void) strcpy(msg
, command
);
2573 (void) strcat(msg
, ": ");
2576 (void) strcat(msg
, s
);
2578 (void) strcat(msg
, q
);
2579 (void) strcat(msg
, "\n");
2580 (void) write(2, msg
, (size_t)strlen(msg
));
2585 abend(const char *s
, const char *q
)
2587 (void) thr_sigsetmask(SIG_SETMASK
, &fillset
, NULL
);
2591 clear_breakpoints();
2592 (void) Punsetflags(Proc
, PR_ASYNC
);
2593 Prelease(Proc
, created
? PRELEASE_KILL
: PRELEASE_CLEAR
);
2604 * If allocation fails then print a message and abort.
2607 my_realloc(void *buf
, size_t size
, const char *msg
)
2609 if ((buf
= realloc(buf
, size
)) == NULL
) {
2611 abend("cannot allocate ", msg
);
2613 abend("memory allocation failure", NULL
);
2620 my_calloc(size_t nelem
, size_t elsize
, const char *msg
)
2624 if ((buf
= calloc(nelem
, elsize
)) == NULL
) {
2626 abend("cannot allocate ", msg
);
2628 abend("memory allocation failure", NULL
);
2635 my_malloc(size_t size
, const char *msg
)
2637 return (my_realloc(NULL
, size
, msg
));
2648 for (i
= 0; i
< 10; i
++) {
2649 while ((pid
= wait(&status
)) != -1) {
2650 /* return exit() code of the created process */
2651 if (pid
== created
) {
2652 if (WIFEXITED(status
))
2653 rc
= WEXITSTATUS(status
);
2655 rc
|= 0x80; /* +128 to indicate sig */
2658 if (errno
!= EINTR
&& errno
!= ERESTART
)
2662 if (i
>= 10) /* repeated interrupts */
2669 letgo(private_t
*pri
)
2671 (void) printf("%s\t*** process otherwise traced, releasing ...\n",
2676 * Test for empty set.
2677 * support routine used by isemptyset() macro.
2680 is_empty(const uint32_t *sp
, /* pointer to set (array of int32's) */
2681 size_t n
) /* number of int32's in set */
2694 * OR the second set into the first.
2695 * The sets must be the same size.
2698 or_set(uint32_t *sp1
, const uint32_t *sp2
, size_t n
)