#include <stdio.h>
#include <stdio_ext.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <memory.h>
#include <signal.h>
#include <wait.h>
#include <limits.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/fstyp.h>
#include <sys/fsid.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <libproc.h>
#include <priv.h>
#include "ramdata.h"
#include "proto.h"
#include "htbl.h"
typedef struct proc_set {
pid_t pid;
const char *lwps;
} proc_set_t;
void setup_basetime(hrtime_t, struct timeval *);
int xcreat(char *);
void setoutput(int);
void report(private_t *, time_t);
void prtim(timestruc_t *);
void pids(char *, proc_set_t *);
void psargs(private_t *);
int control(private_t *, pid_t);
int grabit(private_t *, proc_set_t *);
void release(private_t *, pid_t);
void intr(int);
int wait4all(void);
void letgo(private_t *);
void child_to_file();
void file_to_parent();
void per_proc_init();
int lib_sort(const void *, const void *);
int key_sort(const void *, const void *);
void *worker_thread(void *);
void main_thread(int);
int is_empty(const uint32_t *, size_t);
#define isemptyset(sp) \
is_empty((uint32_t *)(sp), sizeof (*(sp)) / sizeof (uint32_t))
void or_set(uint32_t *, const uint32_t *, size_t);
#define prorset(sp1, sp2) \
or_set((uint32_t *)(sp1), (uint32_t *)(sp2), \
sizeof (*(sp1)) / sizeof (uint32_t))
private_t *
get_private()
{
void *value;
private_t *pri = NULL;
if (thr_getspecific(private_key, &value) == 0)
pri = value;
if (pri == NULL) {
pri = my_malloc(sizeof (*pri), NULL);
(void) memset(pri, 0, sizeof (*pri));
pri->sys_path = my_malloc(pri->sys_psize = 16, NULL);
pri->sys_string = my_malloc(pri->sys_ssize = 32, NULL);
if (thr_setspecific(private_key, pri) == ENOMEM)
abend("memory allocation failure", NULL);
}
return (pri);
}
void
free_private(void *value)
{
private_t *pri = value;
if (pri->sys_path)
free(pri->sys_path);
if (pri->sys_string)
free(pri->sys_string);
if (pri->exec_string)
free(pri->exec_string);
if (pri->str_buffer)
free(pri->str_buffer);
free(pri);
}
void
insert_lwpid(lwpid_t lwpid)
{
int i;
truss_nlwp++;
for (i = 0; i < truss_maxlwp; i++) {
if (truss_lwpid[i] == 0)
break;
}
if (i == truss_maxlwp) {
truss_lwpid = my_realloc(truss_lwpid,
truss_maxlwp * 2 * sizeof (lwpid_t), NULL);
(void) memset(&truss_lwpid[truss_maxlwp], 0,
truss_maxlwp * sizeof (lwpid_t));
truss_maxlwp *= 2;
}
truss_lwpid[i] = lwpid;
}
void
broadcast_signals(void)
{
static int int_notified = FALSE;
static int usr1_notified = FALSE;
static int usr2_notified = FALSE;
lwpid_t my_id = thr_self();
lwpid_t lwpid;
int i;
if (interrupt && !int_notified) {
int_notified = TRUE;
for (i = 0; i < truss_maxlwp; i++) {
if ((lwpid = truss_lwpid[i]) != 0 && lwpid != my_id)
(void) thr_kill(lwpid, interrupt);
}
}
if (sigusr1 && !usr1_notified) {
usr1_notified = TRUE;
for (i = 0; i < truss_maxlwp; i++) {
if ((lwpid = truss_lwpid[i]) != 0 && lwpid != my_id)
(void) thr_kill(lwpid, SIGUSR1);
}
}
if (leave_hung && !usr2_notified) {
usr2_notified = TRUE;
for (i = 0; i < truss_maxlwp; i++) {
if ((lwpid = truss_lwpid[i]) != 0 && lwpid != my_id)
(void) thr_kill(lwpid, SIGUSR2);
}
}
}
static struct ps_lwphandle *
grab_lwp(lwpid_t who)
{
struct ps_lwphandle *Lwp;
int gcode;
if ((Lwp = Lgrab(Proc, who, &gcode)) == NULL) {
if (gcode != G_NOPROC) {
(void) fprintf(stderr,
"%s: cannot grab LWP %u in process %d,"
" reason: %s\n",
command, who, (int)Pstatus(Proc)->pr_pid,
Lgrab_error(gcode));
interrupt = SIGTERM;
}
}
return (Lwp);
}
int
create_thread(void *arg, const lwpstatus_t *Lsp)
{
struct ps_lwphandle *new_Lwp;
lwpid_t lwpid;
int *count = arg;
if (lwptrace(Pstatus(Proc)->pr_pid, Lsp->pr_lwpid))
*count += 1;
if ((new_Lwp = grab_lwp(Lsp->pr_lwpid)) != NULL) {
if (thr_create(NULL, 0, worker_thread, new_Lwp,
THR_BOUND | THR_SUSPENDED, &lwpid) != 0)
abend("cannot create lwp to follow child lwp", NULL);
insert_lwpid(lwpid);
}
return (0);
}
int
main(int argc, char *argv[])
{
private_t *pri;
struct tms tms;
struct rlimit rlim;
int ofd = -1;
int opt;
int i;
int first;
int errflg = FALSE;
int badname = FALSE;
proc_set_t *grab = NULL;
const pstatus_t *Psp;
const lwpstatus_t *Lsp;
int sharedmem;
Cp = NULL;
fcall_tbl = NULL;
while ((i = open("/dev/null", O_RDWR)) >= 0 && i < 2)
;
if (i > 2)
(void) close(i);
starttime = times(&tms);
pagesize = sysconf(_SC_PAGESIZE);
if ((command = strrchr(argv[0], '/')) != NULL)
command++;
else
command = argv[0];
(void) mutex_init(&truss_lock, USYNC_THREAD, NULL);
(void) mutex_init(&count_lock, USYNC_THREAD, NULL);
(void) cond_init(&truss_cv, USYNC_THREAD, NULL);
if (thr_keycreate(&private_key, free_private) == ENOMEM)
abend("memory allocation failure", NULL);
pri = get_private();
Euid = geteuid();
Egid = getegid();
Ruid = getuid();
Rgid = getgid();
ancestor = getpid();
prfillset(&trace);
premptyset(&verbose);
premptyset(&rawout);
prfillset(&signals);
prfillset(&faults);
prdelset(&faults, FLTPAGE);
premptyset(&readfd);
premptyset(&writefd);
premptyset(&syshang);
premptyset(&sighang);
premptyset(&flthang);
(void) sigemptyset(&emptyset);
(void) sigfillset(&fillset);
#define OPTIONS "FpfcaeildDEht:T:v:x:s:S:m:M:u:U:r:w:o:"
while ((opt = getopt(argc, argv, OPTIONS)) != EOF) {
switch (opt) {
case 'F':
Fflag = PGRAB_FORCE;
break;
case 'p':
pflag = TRUE;
break;
case 'f':
fflag = TRUE;
break;
case 'c':
cflag = TRUE;
iflag = TRUE;
break;
case 'a':
aflag = TRUE;
break;
case 'e':
eflag = TRUE;
break;
case 'i':
iflag = TRUE;
break;
case 'l':
lflag = TRUE;
break;
case 'h':
hflag = TRUE;
break;
case 'd':
dflag = TRUE;
break;
case 'D':
Dflag = TRUE;
break;
case 'E':
Eflag = TRUE;
break;
case 't':
if (syslist(optarg, &trace, &tflag))
badname = TRUE;
break;
case 'T':
if (syslist(optarg, &syshang, &Tflag))
badname = TRUE;
break;
case 'v':
if (syslist(optarg, &verbose, &vflag))
badname = TRUE;
break;
case 'x':
if (syslist(optarg, &rawout, &xflag))
badname = TRUE;
break;
case 's':
if (siglist(pri, optarg, &signals, &sflag))
badname = TRUE;
break;
case 'S':
if (siglist(pri, optarg, &sighang, &Sflag))
badname = TRUE;
break;
case 'm':
if (fltlist(optarg, &faults, &mflag))
badname = TRUE;
break;
case 'M':
if (fltlist(optarg, &flthang, &Mflag))
badname = TRUE;
break;
case 'u':
if (liblist(optarg, 0))
badname = TRUE;
break;
case 'U':
if (liblist(optarg, 1))
badname = TRUE;
break;
case 'r':
if (fdlist(optarg, &readfd))
badname = TRUE;
break;
case 'w':
if (fdlist(optarg, &writefd))
badname = TRUE;
break;
case 'o':
oflag = TRUE;
if (ofd >= 0)
(void) close(ofd);
if ((ofd = xcreat(optarg)) < 0) {
perror(optarg);
badname = TRUE;
}
break;
default:
errflg = TRUE;
break;
}
}
if (badname)
exit(2);
if (aflag || eflag)
praddset(&trace, SYS_execve);
prorset(&trace, &syshang);
prorset(&signals, &sighang);
prorset(&faults, &flthang);
argc -= optind;
argv += optind;
if (pflag && argc > 0) {
grab = my_malloc(argc * sizeof (proc_set_t),
"memory for process-ids");
while (argc-- > 0)
pids(*argv++, grab);
}
if (errflg || (argc <= 0 && ngrab <= 0)) {
(void) fprintf(stderr,
"usage:\t%s [-fcaeildDEF] [-[tTvx] [!]syscalls] [-[sS] [!]signals]\\\n",
command);
(void) fprintf(stderr,
"\t[-[mM] [!]faults] [-[rw] [!]fds] [-[uU] [!]libs:[:][!]funcs]\\\n");
(void) fprintf(stderr,
"\t[-o outfile] command | -p pid[/lwps] ...\n");
exit(2);
}
if (argc > 0) {
int err;
char path[PATH_MAX];
Proc = Pcreate(argv[0], &argv[0], &err, path, sizeof (path));
if (Proc == NULL) {
switch (err) {
case C_PERM:
(void) fprintf(stderr,
"%s: cannot trace set-id or "
"unreadable object file: %s\n",
command, path);
break;
case C_LP64:
(void) fprintf(stderr,
"%s: cannot control _LP64 "
"program: %s\n",
command, path);
break;
case C_NOEXEC:
(void) fprintf(stderr,
"%s: cannot execute program: %s\n",
command, argv[0]);
break;
case C_NOENT:
(void) fprintf(stderr,
"%s: cannot find program: %s\n",
command, argv[0]);
break;
case C_STRANGE:
break;
default:
(void) fprintf(stderr, "%s: %s\n",
command, Pcreate_error(err));
break;
}
exit(2);
}
if (fflag || Dynpat != NULL)
(void) Psetflags(Proc, PR_FORK);
else
(void) Punsetflags(Proc, PR_FORK);
Psp = Pstatus(Proc);
Lsp = &Psp->pr_lwp;
pri->lwpstat = Lsp;
data_model = Psp->pr_dmodel;
created = Psp->pr_pid;
make_pname(pri, 0);
(void) sysentry(pri, 1);
pri->length = 0;
if (!cflag && prismember(&trace, SYS_execve)) {
pri->exec_string = my_realloc(pri->exec_string,
strlen(pri->sys_string) + 1, NULL);
(void) strcpy(pri->exec_pname, pri->pname);
(void) strcpy(pri->exec_string, pri->sys_string);
pri->length += strlen(pri->sys_string);
pri->exec_lwpid = pri->lwpstat->pr_lwpid;
pri->sys_leng = 0;
*pri->sys_string = '\0';
}
pri->syslast = Psp->pr_stime;
pri->usrlast = Psp->pr_utime;
}
rlim.rlim_cur = 1024 * 1024;
rlim.rlim_max = 1024 * 1024;
if ((Euid != 0 || setrlimit(RLIMIT_NOFILE, &rlim) != 0) &&
getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
rlim.rlim_cur = rlim.rlim_max;
(void) setrlimit(RLIMIT_NOFILE, &rlim);
}
(void) enable_extended_FILE_stdio(-1, -1);
setoutput(ofd);
istty = isatty(1);
if (setvbuf(stdout, (char *)NULL, _IOFBF, MYBUFSIZ) != 0)
abend("setvbuf() failure", NULL);
if (created && (oflag || !istty)) {
(void) sigset(SIGHUP, SIG_IGN);
(void) sigset(SIGINT, SIG_IGN);
(void) sigset(SIGQUIT, SIG_IGN);
} else {
if (sigset(SIGHUP, SIG_IGN) == SIG_DFL)
(void) sigset(SIGHUP, intr);
if (sigset(SIGINT, SIG_IGN) == SIG_DFL)
(void) sigset(SIGINT, intr);
if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL)
(void) sigset(SIGQUIT, intr);
}
(void) sigset(SIGTERM, intr);
(void) sigset(SIGUSR1, intr);
(void) sigset(SIGUSR2, intr);
(void) sigset(SIGPIPE, intr);
(void) sigset(SIGCLD, SIG_IGN);
sharedmem = (fflag || Dynpat != NULL || ngrab > 1);
gps = (void *)mmap(NULL, sizeof (struct global_psinfo),
PROT_READ|PROT_WRITE,
MAP_ANON | (sharedmem? MAP_SHARED : MAP_PRIVATE),
-1, (off_t)0);
if (gps == MAP_FAILED)
abend("cannot allocate ", "memory for counts");
i = sharedmem? USYNC_PROCESS : USYNC_THREAD;
(void) mutex_init(&gps->ps_mutex0, i, NULL);
(void) mutex_init(&gps->ps_mutex1, i, NULL);
(void) mutex_init(&gps->fork_lock, i, NULL);
(void) cond_init(&gps->fork_cv, i, NULL);
if (fflag && cflag) {
char *tmps = tempnam("/var/tmp", "truss");
sfd = open(tmps, O_CREAT|O_APPEND|O_EXCL|O_RDWR, 0600);
if (sfd == -1)
abend("Error creating tmpfile", NULL);
if (unlink(tmps) == -1)
abend("Error unlinking tmpfile", NULL);
free(tmps);
tmps = NULL;
}
if (created) {
per_proc_init();
procadd(created, NULL);
show_cred(pri, TRUE, FALSE);
} else {
int gotone = FALSE;
i = 0;
while (i < ngrab) {
if (grabit(pri, &grab[i++])) {
Psp = Pstatus(Proc);
Lsp = &Psp->pr_lwp;
gotone = TRUE;
break;
}
}
if (!gotone)
abend(NULL, NULL);
per_proc_init();
while (i < ngrab) {
proc_set_t *set = &grab[i++];
(void) mutex_lock(&truss_lock);
switch (fork()) {
case -1:
(void) fprintf(stderr,
"%s: cannot fork to control process, pid# %d\n",
command, (int)set->pid);
default:
(void) mutex_unlock(&truss_lock);
continue;
case 0:
(void) mutex_unlock(&truss_lock);
Pfree(Proc);
descendent = TRUE;
if (grabit(pri, set)) {
Psp = Pstatus(Proc);
Lsp = &Psp->pr_lwp;
per_proc_init();
break;
}
exit(2);
}
break;
}
free(grab);
}
if (Rgid != Egid)
(void) setgid(Egid);
if (Ruid != Euid)
(void) setuid(Euid);
if (!created && aflag && prismember(&trace, SYS_execve)) {
psargs(pri);
Flush();
}
if (created && Pstate(Proc) != PS_STOP)
if (!(interrupt | sigusr1))
abend("ASSERT error: process is not stopped", NULL);
traceeven = trace;
praddset(&traceeven, SYS_exit);
praddset(&traceeven, SYS_lwp_create);
praddset(&traceeven, SYS_lwp_exit);
praddset(&traceeven, SYS_execve);
praddset(&traceeven, SYS_openat);
praddset(&traceeven, SYS_openat64);
praddset(&traceeven, SYS_open);
praddset(&traceeven, SYS_open64);
praddset(&traceeven, SYS_vfork);
praddset(&traceeven, SYS_forksys);
praddset(&traceeven, SYS_upanic);
if (!isemptyset(&readfd)) {
praddset(&traceeven, SYS_read);
praddset(&traceeven, SYS_readv);
praddset(&traceeven, SYS_pread);
praddset(&traceeven, SYS_pread64);
praddset(&traceeven, SYS_recv);
praddset(&traceeven, SYS_recvfrom);
praddset(&traceeven, SYS_recvmsg);
}
if (!isemptyset(&writefd)) {
praddset(&traceeven, SYS_write);
praddset(&traceeven, SYS_writev);
praddset(&traceeven, SYS_pwrite);
praddset(&traceeven, SYS_pwrite64);
praddset(&traceeven, SYS_send);
praddset(&traceeven, SYS_sendto);
praddset(&traceeven, SYS_sendmsg);
}
if (cflag || Eflag) {
Psetsysentry(Proc, &traceeven);
}
Psetsysexit(Proc, &traceeven);
if (prismember(&trace, SYS_context)) {
(void) Psysentry(Proc, SYS_context, TRUE);
(void) Psysexit(Proc, SYS_context, FALSE);
prdelset(&traceeven, SYS_context);
}
(void) Psysentry(Proc, SYS_execve, TRUE);
(void) Psysentry(Proc, SYS_exit, TRUE);
(void) Psysentry(Proc, SYS_lwp_exit, TRUE);
(void) Psysentry(Proc, SYS_upanic, TRUE);
(void) Psysexit(Proc, SYS_exit, FALSE);
(void) Psysexit(Proc, SYS_lwp_exit, FALSE);
(void) Psysexit(Proc, SYS_upanic, FALSE);
Psetsignal(Proc, &signals);
Psetfault(Proc, &faults);
if (Dynpat != NULL) {
(void) Pfault(Proc, FLTBPT, TRUE);
(void) Pfault(Proc, FLTTRACE, TRUE);
(void) Psetflags(Proc, PR_BPTADJ);
if ((Lsp->pr_why != PR_SYSENTRY &&
Lsp->pr_why != PR_SYSEXIT) ||
Lsp->pr_what != SYS_execve) {
establish_breakpoints();
establish_stacks();
}
}
(void) Psetflags(Proc, PR_ASYNC);
Psync(Proc);
first = created? FALSE : TRUE;
if (!created &&
((Pstate(Proc) == PS_STOP && Lsp->pr_why == PR_REQUESTED) ||
(Lsp->pr_flags & PR_DSTOP)))
first = FALSE;
main_thread(first);
return (0);
}
void
main_thread(int first)
{
private_t *pri = get_private();
struct tms tms;
int flags;
int retc;
int i;
int count;
(void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL);
primary_lwp = (first && Pstate(Proc) == PS_STOP)?
Pstatus(Proc)->pr_lwp.pr_lwpid : 0;
truss_nlwp = 0;
truss_maxlwp = 1;
truss_lwpid = my_realloc(truss_lwpid, sizeof (lwpid_t), NULL);
truss_lwpid[0] = 0;
count = 0;
(void) Plwp_iter(Proc, create_thread, &count);
if (count == 0) {
(void) printf("(Warning: no matching active LWPs found, "
"waiting)\n");
Flush();
}
(void) mutex_lock(&truss_lock);
for (i = 0; i < truss_maxlwp; i++) {
if (truss_lwpid[i])
(void) thr_continue(truss_lwpid[i]);
}
(void) mutex_unlock(&truss_lock);
while (thr_join(0, NULL, NULL) == 0)
continue;
(void) Punsetflags(Proc, PR_ASYNC);
Psync(Proc);
if (sigusr1)
letgo(pri);
flags = PRELEASE_CLEAR;
if (leave_hung)
flags |= PRELEASE_HANG;
Prelease(Proc, flags);
procdel();
retc = (leave_hung? 0 : wait4all());
if (!descendent) {
interrupt = 0;
if (cflag) {
if (fflag)
file_to_parent();
report(pri, times(&tms) - starttime);
}
} else if (cflag && fflag) {
child_to_file();
}
exit(retc);
}
void *
worker_thread(void *arg)
{
struct ps_lwphandle *Lwp = (struct ps_lwphandle *)arg;
const pstatus_t *Psp = Pstatus(Proc);
const lwpstatus_t *Lsp = Lstatus(Lwp);
struct syscount *scp;
lwpid_t who = Lsp->pr_lwpid;
int first = (who == primary_lwp);
private_t *pri = get_private();
int req_flag = 0;
int leave_it_hung = FALSE;
int reset_traps = FALSE;
int gcode;
int what;
int ow_in_effect = 0;
long ow_syscall = 0;
long ow_subcode = 0;
char *ow_string = NULL;
sysset_t full_set;
sysset_t running_set;
int dotrace = lwptrace(Psp->pr_pid, Lsp->pr_lwpid);
pri->Lwp = Lwp;
pri->lwpstat = Lsp;
pri->syslast = Lsp->pr_stime;
pri->usrlast = Lsp->pr_utime;
make_pname(pri, 0);
prfillset(&full_set);
(void) thr_sigsetmask(SIG_SETMASK, &emptyset, NULL);
for (;;) {
if (interrupt | sigusr1) {
(void) Lstop(Lwp, MILLISEC);
if (Lstate(Lwp) == PS_RUN)
break;
}
if (Lstate(Lwp) == PS_RUN) {
uint_t tout = (iflag || req_flag)? 0 : MILLISEC;
if ((leave_hung | interrupt | sigusr1) &&
(Lsp->pr_flags & (PR_STOPPED|PR_ISTOP))
== PR_STOPPED)
break;
(void) Lwait(Lwp, tout);
if (Lstate(Lwp) == PS_RUN &&
tout != 0 && !(interrupt | sigusr1)) {
(void) mutex_lock(&truss_lock);
if ((Lsp->pr_flags & PR_STOPPED) &&
Lsp->pr_why == PR_JOBCONTROL)
req_flag = jobcontrol(pri, dotrace);
else
req_flag = requested(pri, req_flag,
dotrace);
(void) mutex_unlock(&truss_lock);
}
continue;
}
data_model = Psp->pr_dmodel;
if (Lstate(Lwp) == PS_UNDEAD)
break;
if (Lstate(Lwp) == PS_LOST) {
(void) mutex_lock(&truss_lock);
while (truss_nlwp > 1)
(void) cond_wait(&truss_cv, &truss_lock);
if (Preopen(Proc) == 0) {
who = 1;
Lfree(Lwp);
pri->Lwp = Lwp =
Lgrab(Proc, who, &gcode);
if (Lwp == NULL)
abend("Lgrab error: ",
Lgrab_error(gcode));
pri->lwpstat = Lsp = Lstatus(Lwp);
(void) mutex_unlock(&truss_lock);
continue;
}
if (pri->exec_string && *pri->exec_string) {
if (pri->exec_pname[0] != '\0')
(void) fputs(pri->exec_pname, stdout);
timestamp(pri);
(void) fputs(pri->exec_string, stdout);
(void) fputc('\n', stdout);
} else if (pri->length) {
(void) fputc('\n', stdout);
}
if (pri->sys_valid)
(void) printf(
"%s\t*** cannot trace across exec() of %s ***\n",
pri->pname, pri->sys_path);
else
(void) printf(
"%s\t*** lost control of process ***\n",
pri->pname);
pri->length = 0;
Flush();
(void) mutex_unlock(&truss_lock);
break;
}
if (Lstate(Lwp) != PS_STOP) {
(void) fprintf(stderr,
"%s: state = %d\n", command, Lstate(Lwp));
abend(pri->pname, "uncaught status of subject lwp");
}
make_pname(pri, 0);
(void) mutex_lock(&truss_lock);
what = Lsp->pr_what;
req_flag = 0;
switch (Lsp->pr_why) {
case PR_REQUESTED:
break;
case PR_SIGNALLED:
req_flag = signalled(pri, req_flag, dotrace);
if (Sflag && !first && prismember(&sighang, what))
leave_it_hung = TRUE;
break;
case PR_FAULTED:
if (what == FLTBPT) {
int rval;
(void) Pstop(Proc, 0);
rval = function_trace(pri, first, 0, dotrace);
if (rval == 1)
leave_it_hung = TRUE;
if (rval >= 0)
break;
}
if (faulted(pri, dotrace) &&
Mflag && !first && prismember(&flthang, what))
leave_it_hung = TRUE;
break;
case PR_JOBCONTROL:
req_flag = jobcontrol(pri, dotrace);
break;
case PR_SYSENTRY:
if (what <= 0 || what > PRMAXSYS)
what = PRMAXSYS;
pri->length = 0;
if (dotrace && ow_in_effect) {
if (cflag) {
(void) mutex_lock(&count_lock);
scp = Cp->syscount[ow_syscall];
if (ow_subcode != -1)
scp += ow_subcode;
scp->count++;
accumulate(&scp->stime,
&Lsp->pr_stime, &pri->syslast);
accumulate(&Cp->usrtotal,
&Lsp->pr_utime, &pri->usrlast);
pri->syslast = Lsp->pr_stime;
pri->usrlast = Lsp->pr_utime;
(void) mutex_unlock(&count_lock);
} else if (Eflag) {
putpname(pri);
timestamp(pri);
(void) printf("%s\n", ow_string);
free(ow_string);
ow_string = NULL;
pri->syslast = Lsp->pr_stime;
}
ow_in_effect = 0;
Psetsysentry(Proc, &running_set);
}
switch (what) {
case SYS_exit:
case SYS_lwp_exit:
case SYS_upanic:
case SYS_context:
if (dotrace && cflag &&
prismember(&trace, what)) {
ow_in_effect = 1;
ow_syscall = what;
ow_subcode = getsubcode(pri);
pri->syslast = Lsp->pr_stime;
running_set =
(Pstatus(Proc))->pr_sysentry;
Psetsysentry(Proc, &full_set);
} else if (dotrace && Eflag &&
prismember(&trace, what)) {
(void) sysentry(pri, dotrace);
ow_in_effect = 1;
ow_string = my_malloc(
strlen(pri->sys_string) + 1, NULL);
(void) strcpy(ow_string,
pri->sys_string);
running_set =
(Pstatus(Proc))->pr_sysentry;
Psetsysentry(Proc, &full_set);
pri->syslast = Lsp->pr_stime;
} else if (dotrace &&
prismember(&trace, what)) {
(void) sysentry(pri, dotrace);
putpname(pri);
timestamp(pri);
pri->length +=
printf("%s\n", pri->sys_string);
Flush();
}
pri->sys_leng = 0;
*pri->sys_string = '\0';
if (what == SYS_exit)
exit_called = TRUE;
break;
case SYS_execve:
show_cred(pri, FALSE, TRUE);
(void) sysentry(pri, dotrace);
if (dotrace && !cflag &&
prismember(&trace, what)) {
pri->exec_string =
my_realloc(pri->exec_string,
strlen(pri->sys_string) + 1,
NULL);
(void) strcpy(pri->exec_pname,
pri->pname);
(void) strcpy(pri->exec_string,
pri->sys_string);
pri->length += strlen(pri->sys_string);
pri->exec_lwpid = Lsp->pr_lwpid;
}
pri->sys_leng = 0;
*pri->sys_string = '\0';
break;
default:
if (dotrace && (cflag || Eflag) &&
prismember(&trace, what)) {
pri->syslast = Lsp->pr_stime;
}
break;
}
if (dotrace && Tflag && !first &&
(prismember(&syshang, what) ||
(exit_called && prismember(&syshang, SYS_exit))))
leave_it_hung = TRUE;
break;
case PR_SYSEXIT:
if (what == SYS_openat || what == SYS_openat64 ||
what == SYS_open || what == SYS_open64) {
int readonly;
(void) sysentry(pri, dotrace);
pri->Errno = Lsp->pr_errno;
pri->ErrPriv = Lsp->pr_errpriv;
readonly =
((what == SYS_openat ||
what == SYS_openat64) &&
pri->sys_nargs > 2 &&
(pri->sys_args[2]&0x3) == O_RDONLY) ||
((what == SYS_open ||
what == SYS_open64) &&
pri->sys_nargs > 1 &&
(pri->sys_args[1]&0x3) == O_RDONLY);
if ((pri->Errno == 0 || pri->Errno == EBUSY) &&
pri->sys_valid && !readonly) {
int rv = checkproc(pri);
if (rv == 1 && Fflag != PGRAB_FORCE) {
if (dotrace && !cflag &&
prismember(&trace, what)) {
putpname(pri);
timestamp(pri);
(void) printf("%s\n",
pri->sys_string);
Flush();
}
sigusr1 = TRUE;
(void) mutex_unlock(
&truss_lock);
goto out;
}
if (rv == 2) {
pri->sys_leng = 0;
*pri->sys_string = '\0';
pri->sys_nargs = 0;
break;
}
}
}
if (what == SYS_execve && Lsp->pr_errno == 0) {
(void) Pstopstatus(Proc, PCNULL, 0);
data_model = Psp->pr_dmodel;
}
if (sysexit(pri, dotrace))
Flush();
if (what == SYS_lwp_create && pri->Rval1 != 0) {
struct ps_lwphandle *new_Lwp;
lwpid_t lwpid;
if ((new_Lwp = grab_lwp(pri->Rval1)) != NULL) {
(void) thr_sigsetmask(SIG_SETMASK,
&fillset, NULL);
if (thr_create(NULL, 0, worker_thread,
new_Lwp, THR_BOUND | THR_SUSPENDED,
&lwpid) != 0)
abend("cannot create lwp ",
"to follow child lwp");
insert_lwpid(lwpid);
(void) thr_continue(lwpid);
(void) thr_sigsetmask(SIG_SETMASK,
&emptyset, NULL);
}
}
pri->sys_nargs = 0;
if (dotrace && Tflag && !first &&
prismember(&syshang, what))
leave_it_hung = TRUE;
if (what == SYS_execve && pri->Errno == 0) {
is_vfork_child = FALSE;
reset_breakpoints();
if (who != Lsp->pr_lwpid) {
while (truss_nlwp > 1)
(void) cond_wait(&truss_cv,
&truss_lock);
who = Lsp->pr_lwpid;
Lfree(Lwp);
pri->Lwp = Lwp =
Lgrab(Proc, who, &gcode);
if (Lwp == NULL)
abend("Lgrab error: ",
Lgrab_error(gcode));
pri->lwpstat = Lsp = Lstatus(Lwp);
}
}
break;
default:
req_flag = 0;
(void) fprintf(stderr,
"unknown reason for stopping: %d/%d\n",
Lsp->pr_why, what);
abend(NULL, NULL);
}
if (pri->child) {
if (fflag || Dynpat != NULL) {
if (Lsp->pr_why == PR_SYSEXIT &&
(Lsp->pr_what == SYS_vfork ||
(Lsp->pr_what == SYS_forksys &&
Lsp->pr_sysarg[0] == 2))) {
is_vfork_child = TRUE;
(void) Pstop(Proc, 0);
}
if (control(pri, pri->child)) {
(void) mutex_unlock(&truss_lock);
pri->child = 0;
if (!fflag) {
clear_breakpoints();
Prelease(Proc, PRELEASE_CLEAR);
_exit(0);
}
main_thread(FALSE);
}
if (Dynpat != NULL && is_vfork_child && !fflag)
reset_traps = TRUE;
is_vfork_child = FALSE;
}
pri->child = 0;
}
if (leave_it_hung) {
(void) mutex_unlock(&truss_lock);
break;
}
if (reset_traps) {
reset_traps = FALSE;
(void) Lsetrun(Lwp, 0, PRSTEP);
do {
(void) Lwait(Lwp, 0);
} while (Lstate(Lwp) == PS_RUN);
if (Lstate(Lwp) == PS_STOP &&
Lsp->pr_why == PR_FAULTED &&
Lsp->pr_what == FLTTRACE) {
reestablish_traps();
(void) Lsetrun(Lwp, 0, PRCFAULT|PRSTOP);
} else {
(void) printf("%s\t*** Expected PR_FAULTED/"
"FLTTRACE stop following vfork()\n",
pri->pname);
}
}
if (Lstate(Lwp) == PS_STOP) {
int flags = 0;
if (interrupt | sigusr1) {
(void) mutex_unlock(&truss_lock);
break;
}
if (leave_hung) {
if (Lsp->pr_why == PR_REQUESTED) {
(void) mutex_unlock(&truss_lock);
break;
}
flags |= PRSTOP;
}
if (Lsetrun(Lwp, 0, flags) != 0 &&
Lstate(Lwp) != PS_LOST &&
Lstate(Lwp) != PS_UNDEAD) {
(void) mutex_unlock(&truss_lock);
perror("Lsetrun");
abend("cannot start subject lwp", NULL);
}
}
first = FALSE;
(void) mutex_unlock(&truss_lock);
}
out:
(void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL);
if (Lstate(Lwp) == PS_UNDEAD || Lstate(Lwp) == PS_LOST)
(void) mutex_lock(&truss_lock);
else {
(void) Lstop(Lwp, MILLISEC);
(void) mutex_lock(&truss_lock);
if (Lstate(Lwp) == PS_STOP &&
Lsp->pr_why == PR_FAULTED &&
Lsp->pr_what == FLTBPT)
(void) function_trace(pri, 0, 1, dotrace);
}
if (dotrace && ow_in_effect) {
if (cflag) {
(void) mutex_lock(&count_lock);
scp = Cp->syscount[ow_syscall];
if (ow_subcode != -1)
scp += ow_subcode;
scp->count++;
accumulate(&scp->stime,
&Lsp->pr_stime, &pri->syslast);
accumulate(&Cp->usrtotal,
&Lsp->pr_utime, &pri->usrlast);
pri->syslast = Lsp->pr_stime;
pri->usrlast = Lsp->pr_utime;
(void) mutex_unlock(&count_lock);
} else if (Eflag) {
putpname(pri);
timestamp(pri);
(void) printf("%s\n", ow_string);
free(ow_string);
ow_string = NULL;
pri->syslast = Lsp->pr_stime;
}
ow_in_effect = 0;
Psetsysentry(Proc, &running_set);
}
if (Lstate(Lwp) == PS_UNDEAD || Lstate(Lwp) == PS_LOST) {
lwpid_t my_id = thr_self();
int i;
for (i = 0; i < truss_maxlwp; i++) {
if (truss_lwpid[i] == my_id) {
truss_lwpid[i] = 0;
break;
}
}
if (--truss_nlwp != 0) {
(void) cond_broadcast(&truss_cv);
} else {
report_htable_stats();
}
} else {
static int nstopped = 0;
static int cleared = 0;
if (leave_it_hung)
leave_hung = TRUE;
if ((leave_hung | interrupt | sigusr1) == 0)
abend("(leave_hung | interrupt | sigusr1) == 0", NULL);
if (nstopped++ == 0)
(void) Pdstop(Proc);
broadcast_signals();
while (nstopped != truss_nlwp)
(void) cond_wait(&truss_cv, &truss_lock);
if (cleared++ == 0) {
(void) Pstop(Proc, MILLISEC);
clear_breakpoints();
(void) Psysexit(Proc, SYS_vfork, FALSE);
(void) Psysexit(Proc, SYS_forksys, FALSE);
(void) Punsetflags(Proc, PR_FORK);
Psync(Proc);
fflag = 0;
(void) cond_broadcast(&truss_cv);
}
if (!leave_hung && Lstate(Lwp) == PS_STOP)
(void) Lsetrun(Lwp, 0, 0);
}
(void) Lfree(Lwp);
(void) mutex_unlock(&truss_lock);
return (NULL);
}
void
setup_basetime(hrtime_t basehrtime, struct timeval *basedate)
{
const pstatus_t *Psp = Pstatus(Proc);
(void) mutex_lock(&count_lock);
Cp->basetime = Psp->pr_lwp.pr_tstamp;
(void) mutex_unlock(&count_lock);
if ((dflag|Dflag) && !cflag) {
const struct tm *ptm;
const char *ptime;
const char *pdst;
hrtime_t delta = basehrtime -
((hrtime_t)Cp->basetime.tv_sec * NANOSEC +
Cp->basetime.tv_nsec);
if (delta > 0) {
basedate->tv_sec -= (time_t)(delta / NANOSEC);
basedate->tv_usec -= (delta % NANOSEC) / 1000;
if (basedate->tv_usec < 0) {
basedate->tv_sec--;
basedate->tv_usec += MICROSEC;
}
}
ptm = localtime(&basedate->tv_sec);
ptime = asctime(ptm);
if ((pdst = tzname[ptm->tm_isdst ? 1 : 0]) == NULL)
pdst = "???";
if (dflag) {
(void) printf(
"Base time stamp: %ld.%4.4ld [ %.20s%s %.4s ]\n",
basedate->tv_sec, basedate->tv_usec / 100,
ptime, pdst, ptime + 20);
Flush();
}
}
}
void
per_proc_init()
{
void *pmem;
struct timeval basedate;
hrtime_t basehrtime;
struct syscount *scp;
int i;
timestruc_t c_basetime;
if (Cp == NULL) {
pmem = my_malloc(sizeof (struct counts) + maxsyscalls() *
sizeof (struct syscount), NULL);
Cp = (struct counts *)pmem;
basehrtime = gethrtime();
(void) gettimeofday(&basedate, NULL);
setup_basetime(basehrtime, &basedate);
}
c_basetime = Cp->basetime;
(void) memset(Cp, 0, sizeof (struct counts) + maxsyscalls() *
sizeof (struct syscount));
Cp->basetime = c_basetime;
if (fcall_tbl != NULL)
destroy_hash(fcall_tbl);
fcall_tbl = init_hash(4096);
(void) mutex_lock(&count_lock);
scp = (struct syscount *)(Cp + 1);
for (i = 0; i <= PRMAXSYS; i++) {
Cp->syscount[i] = scp;
scp += nsubcodes(i);
}
(void) mutex_unlock(&count_lock);
}
void
child_to_file()
{
hiter_t *itr;
hentry_t *ntry;
hdntry_t fentry;
char *s = NULL;
char *t = NULL;
unsigned char *buf = NULL;
size_t bufsz = 0;
size_t i = 0;
size_t j = 0;
if (!descendent)
return;
if (Dynpat != NULL) {
itr = iterate_hash(fcall_tbl);
ntry = iter_next(itr);
while (ntry != NULL) {
fentry.type = HD_hashntry;
fentry.count = ntry->count;
s = ntry->key;
t = ntry->lib;
i = strlen(s) + 1;
j = strlen(t) + 1;
fentry.sz_key = i;
fentry.sz_lib = j;
if (i + sizeof (fentry) > bufsz) {
buf = my_realloc(buf, i + j + sizeof (fentry),
NULL);
bufsz = i + j + sizeof (fentry);
}
(void) memcpy(buf, &fentry, sizeof (fentry));
(void) strlcpy((char *)(buf + sizeof (fentry)), t, j);
(void) strlcpy((char *)(buf + sizeof (fentry) + j),
s, i);
if (write(sfd, buf, sizeof (fentry) + i + j) == -1)
abend("Error writing to tmp file", NULL);
ntry = iter_next(itr);
}
iter_free(itr);
}
bufsz = sizeof (fentry) + (sizeof (struct counts) + maxsyscalls() *
sizeof (struct syscount));
buf = my_realloc(buf, bufsz, NULL);
fentry.type = HD_cts_syscts;
fentry.count = 0;
fentry.sz_key = bufsz - sizeof (fentry);
fentry.sz_lib = 0;
(void) memcpy(buf, &fentry, sizeof (fentry));
(void) memcpy((char *)(buf + sizeof (fentry)), Cp,
bufsz - sizeof (fentry));
if (write(sfd, buf, bufsz) == -1)
abend("Error writing cts/syscts to tmpfile", NULL);
free(buf);
}
void
file_to_parent()
{
hdntry_t ntry;
char *s = NULL;
char *t = NULL;
size_t c_offset = 0;
size_t filesz;
size_t t_strsz = 0;
size_t s_strsz = 0;
struct stat fsi;
if (descendent)
return;
if (fstat(sfd, &fsi) == -1)
abend("Error stat-ing tempfile", NULL);
filesz = fsi.st_size;
while (c_offset < filesz) {
if (pread(sfd, &ntry, sizeof (hdntry_t), c_offset) !=
sizeof (hdntry_t))
abend("Unable to perform full read of hdntry", NULL);
c_offset += sizeof (hdntry_t);
switch (ntry.type) {
case HD_hashntry:
if (ntry.sz_lib > t_strsz) {
t = my_realloc(t, ntry.sz_lib, NULL);
t_strsz = ntry.sz_lib;
}
(void) memset(t, 0, t_strsz);
if (pread(sfd, t, ntry.sz_lib, c_offset) != ntry.sz_lib)
abend("Unable to perform full read of lib str",
NULL);
c_offset += ntry.sz_lib;
if (ntry.sz_key > s_strsz) {
s = my_realloc(s, ntry.sz_key, NULL);
s_strsz = ntry.sz_key;
}
(void) memset(s, 0, s_strsz);
if (pread(sfd, s, ntry.sz_key, c_offset) != ntry.sz_key)
abend("Unable to perform full read of key str",
NULL);
c_offset += ntry.sz_key;
add_fcall(fcall_tbl, t, s, ntry.count);
break;
case HD_cts_syscts:
{
struct counts *ncp;
size_t bfsz = sizeof (struct counts) + maxsyscalls()
* sizeof (struct syscount);
int i;
struct syscount *sscp;
if (ntry.sz_key != bfsz)
abend("cts/syscts size does not sanity check",
NULL);
ncp = my_malloc(ntry.sz_key, NULL);
if (pread(sfd, ncp, ntry.sz_key, c_offset) !=
ntry.sz_key)
abend("Unable to perform full read of cts",
NULL);
c_offset += ntry.sz_key;
sscp = (struct syscount *)(ncp + 1);
(void) mutex_lock(&count_lock);
Cp->usrtotal.tv_sec += ncp->usrtotal.tv_sec;
Cp->usrtotal.tv_nsec += ncp->usrtotal.tv_nsec;
if (Cp->usrtotal.tv_nsec >= NANOSEC) {
Cp->usrtotal.tv_nsec -= NANOSEC;
Cp->usrtotal.tv_sec++;
}
for (i = 0; i <= PRMAXSYS; i++) {
ncp->syscount[i] = sscp;
sscp += nsubcodes(i);
}
for (i = 0; i <= PRMAXFAULT; i++) {
Cp->fltcount[i] += ncp->fltcount[i];
}
for (i = 0; i <= PRMAXSIG; i++) {
Cp->sigcount[i] += ncp->sigcount[i];
}
for (i = 0; i <= PRMAXSYS; i++) {
struct syscount *scp = Cp->syscount[i];
struct syscount *nscp = ncp->syscount[i];
int n = nsubcodes(i);
int subcode;
for (subcode = 0; subcode < n; subcode++,
scp++, nscp++) {
scp->count += nscp->count;
scp->error += nscp->error;
scp->stime.tv_sec += nscp->stime.tv_sec;
scp->stime.tv_nsec +=
nscp->stime.tv_nsec;
if (scp->stime.tv_nsec >= NANOSEC) {
scp->stime.tv_nsec -= NANOSEC;
scp->stime.tv_sec++;
}
}
}
(void) mutex_unlock(&count_lock);
free(ncp);
break;
}
default:
abend("Unknown file entry type encountered", NULL);
break;
}
if (fstat(sfd, &fsi) == -1)
abend("Error stat-ing tempfile", NULL);
filesz = fsi.st_size;
}
if (s != NULL)
free(s);
if (t != NULL)
free(t);
}
void
make_pname(private_t *pri, id_t tid)
{
if (!cflag) {
int ff = (fflag || ngrab > 1);
int lf = (lflag | tid | (Thr_agent != NULL) | (truss_nlwp > 1));
pid_t pid = Pstatus(Proc)->pr_pid;
id_t lwpid = pri->lwpstat->pr_lwpid;
if (ff != pri->pparam.ff ||
lf != pri->pparam.lf ||
pid != pri->pparam.pid ||
lwpid != pri->pparam.lwpid ||
tid != pri->pparam.tid) {
char *s = pri->pname;
if (ff)
s += sprintf(s, "%d", (int)pid);
if (lf)
s += sprintf(s, "/%d", (int)lwpid);
if (tid)
s += sprintf(s, "@%d", (int)tid);
if (ff || lf)
*s++ = ':', *s++ = '\t';
if (ff && lf && s < pri->pname + 9)
*s++ = '\t';
*s = '\0';
pri->pparam.ff = ff;
pri->pparam.lf = lf;
pri->pparam.pid = pid;
pri->pparam.lwpid = lwpid;
pri->pparam.tid = tid;
}
}
}
void
putpname(private_t *pri)
{
if (pri->pname[0])
(void) fputs(pri->pname, stdout);
}
void
timestamp(private_t *pri)
{
const lwpstatus_t *Lsp = pri->lwpstat;
int seconds;
int fraction;
if (!(dflag|Dflag|Eflag) || !(Lsp->pr_flags & PR_STOPPED))
return;
seconds = Lsp->pr_tstamp.tv_sec - Cp->basetime.tv_sec;
fraction = Lsp->pr_tstamp.tv_nsec - Cp->basetime.tv_nsec;
if (fraction < 0) {
seconds--;
fraction += NANOSEC;
}
fraction = (fraction + 50000) / 100000;
if (fraction >= (MILLISEC * 10)) {
seconds++;
fraction -= (MILLISEC * 10);
}
if (dflag)
(void) printf("%2d.%4.4d\t", seconds, fraction);
if (Dflag) {
int oseconds = pri->seconds;
int ofraction = pri->fraction;
pri->seconds = seconds;
pri->fraction = fraction;
seconds -= oseconds;
fraction -= ofraction;
if (fraction < 0) {
seconds--;
fraction += (MILLISEC * 10);
}
(void) printf("%2d.%4.4d\t", seconds, fraction);
}
if (Eflag) {
seconds = Lsp->pr_stime.tv_sec - pri->syslast.tv_sec;
fraction = Lsp->pr_stime.tv_nsec - pri->syslast.tv_nsec;
if (fraction < 0) {
seconds--;
fraction += NANOSEC;
}
fraction = (fraction + 50000) / 100000;
if (fraction >= (MILLISEC * 10)) {
seconds++;
fraction -= (MILLISEC * 10);
}
(void) printf("%2d.%4.4d\t", seconds, fraction);
}
}
int
xcreat(char *path)
{
int fd;
int mode = 0666;
if (Euid == Ruid && Egid == Rgid)
fd = creat(path, mode);
else if (access(path, F_OK) != 0) {
char *dir;
char *p;
char dot[4];
if ((p = strrchr(path, '/')) == NULL) {
p = dir = dot;
*p++ = '.';
*p = '\0';
} else if (p == path) {
p = dir = dot;
*p++ = '/';
*p = '\0';
} else {
dir = path;
*p = '\0';
}
if (access(dir, W_OK|X_OK) != 0) {
*p = '/';
fd = -1;
} else {
*p = '/';
if ((fd = creat(path, mode)) >= 0)
(void) chown(path, (int)Ruid, (int)Rgid);
}
} else if (access(path, W_OK) != 0)
fd = -1;
else
fd = creat(path, mode);
if (0 <= fd && fd <= 2) {
int dfd = fcntl(fd, F_DUPFD, 3);
(void) close(fd);
fd = dfd;
}
if (fd >= 0)
(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
return (fd);
}
void
setoutput(int ofd)
{
if (ofd < 0) {
(void) close(1);
(void) fcntl(2, F_DUPFD, 1);
} else if (ofd != 1) {
(void) close(1);
(void) fcntl(ofd, F_DUPFD, 1);
(void) close(ofd);
if ((ofd = dup(2)) < 0)
(void) fcntl(1, F_DUPFD, 2);
else
(void) close(ofd);
}
}
void
accumulate(timestruc_t *ap, const timestruc_t *ep, const timestruc_t *sp)
{
ap->tv_sec += ep->tv_sec - sp->tv_sec;
ap->tv_nsec += ep->tv_nsec - sp->tv_nsec;
if (ap->tv_nsec >= NANOSEC) {
ap->tv_nsec -= NANOSEC;
ap->tv_sec++;
} else if (ap->tv_nsec < 0) {
ap->tv_nsec += NANOSEC;
ap->tv_sec--;
}
}
int
lib_sort(const void *p1, const void *p2)
{
int cmpr = 0;
long i;
long j;
hentry_t *t1 = (hentry_t *)p1;
hentry_t *t2 = (hentry_t *)p2;
char *p = t1->lib;
char *q = t2->lib;
if ((cmpr = strcmp(p, q)) == 0) {
i = t1->count;
j = t2->count;
if (i > j)
return (-1);
else if (i < j)
return (1);
else {
p = t1->key;
q = t2->key;
return (strcmp(p, q));
}
} else
return (cmpr);
}
void
report(private_t *pri, time_t lapse)
{
int i;
long count;
const char *name;
long error;
long total;
long errtot;
timestruc_t tickzero;
timestruc_t ticks;
timestruc_t ticktot;
if (descendent)
return;
for (i = 0, total = 0; i <= PRMAXFAULT && !interrupt; i++) {
if ((count = Cp->fltcount[i]) != 0) {
if (total == 0)
(void) printf("faults -------------\n");
name = proc_fltname(i, pri->flt_name,
sizeof (pri->flt_name));
(void) printf("%s%s\t%4ld\n", name,
(((int)strlen(name) < 8)?
(const char *)"\t" : (const char *)""),
count);
total += count;
}
}
if (total && !interrupt)
(void) printf("total:\t\t%4ld\n\n", total);
for (i = 0, total = 0; i <= PRMAXSIG && !interrupt; i++) {
if ((count = Cp->sigcount[i]) != 0) {
if (total == 0)
(void) printf("signals ------------\n");
name = signame(pri, i);
(void) printf("%s%s\t%4ld\n", name,
(((int)strlen(name) < 8)?
(const char *)"\t" : (const char *)""),
count);
total += count;
}
}
if (total && !interrupt)
(void) printf("total:\t\t%4ld\n\n", total);
if ((Dynpat != NULL) && !interrupt) {
size_t elem = elements_in_table(fcall_tbl);
hiter_t *itr = iterate_hash(fcall_tbl);
hentry_t *tmp = iter_next(itr);
hentry_t *stbl = my_malloc(elem * sizeof (hentry_t), NULL);
i = 0;
while ((tmp != NULL) && (i < elem)) {
stbl[i].prev = tmp->prev;
stbl[i].next = tmp->next;
stbl[i].lib = tmp->lib;
stbl[i].key = tmp->key;
stbl[i].count = tmp->count;
tmp = iter_next(itr);
i++;
}
qsort((void *)stbl, elem, sizeof (hentry_t),
lib_sort);
(void) printf(
"\n%-20s %-40s %s\n", "Library:", "Function", "calls");
for (i = 0; i < elem; i++) {
(void) printf("%-20s %-40s %ld\n", stbl[i].lib,
stbl[i].key, stbl[i].count);
}
iter_free(itr);
free(stbl);
itr = NULL;
}
if (!interrupt)
(void) printf(
"\nsyscall seconds calls errors\n");
total = errtot = 0;
tickzero.tv_sec = ticks.tv_sec = ticktot.tv_sec = 0;
tickzero.tv_nsec = ticks.tv_nsec = ticktot.tv_nsec = 0;
for (i = 0; i <= PRMAXSYS && !interrupt; i++) {
struct syscount *scp = Cp->syscount[i];
int n = nsubcodes(i);
int subcode;
for (subcode = 0; subcode < n; subcode++, scp++) {
if ((count = scp->count) != 0 || scp->error) {
(void) printf("%-19.19s ",
sysname(pri, i, subcode));
ticks = scp->stime;
accumulate(&ticktot, &ticks, &tickzero);
prtim(&ticks);
(void) printf(" %7ld", count);
if ((error = scp->error) != 0)
(void) printf(" %7ld", error);
(void) fputc('\n', stdout);
total += count;
errtot += error;
}
}
}
if (!interrupt) {
(void) printf(
" -------- ------ ----\n");
(void) printf("sys totals: ");
prtim(&ticktot);
(void) printf(" %7ld %6ld\n", total, errtot);
}
if (!interrupt) {
(void) printf("usr time: ");
prtim(&Cp->usrtotal);
(void) fputc('\n', stdout);
}
if (!interrupt) {
int hz = (int)sysconf(_SC_CLK_TCK);
ticks.tv_sec = lapse / hz;
ticks.tv_nsec = (lapse % hz) * (1000000000 / hz);
(void) printf("elapsed: ");
prtim(&ticks);
(void) fputc('\n', stdout);
}
}
void
prtim(timestruc_t *tp)
{
time_t sec;
if ((sec = tp->tv_sec) != 0)
(void) printf("%5lu", sec);
else
(void) printf(" ");
(void) printf(".%3.3ld", tp->tv_nsec/1000000);
}
void
pids(char *arg, proc_set_t *grab)
{
pid_t pid = -1;
int i;
const char *lwps = NULL;
if ((pid = proc_arg_xpsinfo(arg, PR_ARG_PIDS, NULL, &i, &lwps)) < 0) {
(void) fprintf(stderr, "%s: cannot trace '%s': %s\n",
command, arg, Pgrab_error(i));
return;
}
for (i = 0; i < ngrab; i++)
if (grab[i].pid == pid)
break;
if (i == ngrab) {
grab[ngrab].pid = pid;
grab[ngrab].lwps = lwps;
ngrab++;
} else {
(void) fprintf(stderr, "%s: duplicate process-id ignored: %d\n",
command, (int)pid);
}
}
void
psargs(private_t *pri)
{
pid_t pid = Pstatus(Proc)->pr_pid;
psinfo_t psinfo;
if (proc_get_psinfo(pid, &psinfo) == 0)
(void) printf("%spsargs: %.64s\n",
pri->pname, psinfo.pr_psargs);
else {
perror("psargs()");
(void) printf("%s\t*** Cannot read psinfo file for pid %d\n",
pri->pname, (int)pid);
}
}
char *
fetchstring(private_t *pri, long addr, int maxleng)
{
int nbyte;
int leng = 0;
char string[41];
string[40] = '\0';
if (pri->str_bsize == 0)
pri->str_buffer =
my_malloc(pri->str_bsize = 16, "string buffer");
*pri->str_buffer = '\0';
for (nbyte = 40; nbyte == 40 && leng < maxleng; addr += 40) {
if ((nbyte = Pread(Proc, string, 40, addr)) <= 0)
return (leng? pri->str_buffer : NULL);
if (nbyte > 0 &&
(nbyte = strlen(string)) > 0) {
while (leng + nbyte >= pri->str_bsize)
pri->str_buffer =
my_realloc(pri->str_buffer,
pri->str_bsize *= 2, "string buffer");
(void) strcpy(pri->str_buffer+leng, string);
leng += nbyte;
}
}
if (leng > maxleng)
leng = maxleng;
pri->str_buffer[leng] = '\0';
return (pri->str_buffer);
}
static priv_set_t *
getset(prpriv_t *p, priv_ptype_t set)
{
return ((priv_set_t *)
&p->pr_sets[priv_getsetbyname(set) * p->pr_setsize]);
}
void
show_cred(private_t *pri, int new, int loadonly)
{
prcred_t cred;
prpriv_t *privs;
if (proc_get_cred(Pstatus(Proc)->pr_pid, &cred, 0) < 0) {
perror("show_cred() - credential");
(void) printf("%s\t*** Cannot get credentials\n", pri->pname);
return;
}
if ((privs = proc_get_priv(Pstatus(Proc)->pr_pid)) == NULL) {
perror("show_cred() - privileges");
(void) printf("%s\t*** Cannot get privileges\n", pri->pname);
return;
}
if (!loadonly && !cflag && prismember(&trace, SYS_execve)) {
if (new)
credentials = cred;
if ((new && cred.pr_ruid != cred.pr_suid) ||
cred.pr_ruid != credentials.pr_ruid ||
cred.pr_suid != credentials.pr_suid)
(void) printf(
"%s *** SUID: ruid/euid/suid = %d / %d / %d ***\n",
pri->pname,
(int)cred.pr_ruid,
(int)cred.pr_euid,
(int)cred.pr_suid);
if ((new && cred.pr_rgid != cred.pr_sgid) ||
cred.pr_rgid != credentials.pr_rgid ||
cred.pr_sgid != credentials.pr_sgid)
(void) printf(
"%s *** SGID: rgid/egid/sgid = %d / %d / %d ***\n",
pri->pname,
(int)cred.pr_rgid,
(int)cred.pr_egid,
(int)cred.pr_sgid);
if (privdata != NULL && cred.pr_euid != 0) {
priv_set_t *npset = getset(privs, PRIV_PERMITTED);
priv_set_t *opset = getset(privdata, PRIV_PERMITTED);
char *s, *t;
if (!priv_issubset(npset, opset)) {
priv_inverse(opset);
priv_intersect(npset, opset);
s = priv_set_to_str(opset, ',', PRIV_STR_SHORT);
t = priv_set_to_str(npset, ',', PRIV_STR_SHORT);
(void) printf("%s *** FPRIV: P/E: %s ***\n",
pri->pname,
strlen(s) > strlen(t) ? t : s);
free(s);
free(t);
}
}
}
if (privdata != NULL)
proc_free_priv(privdata);
credentials = cred;
privdata = privs;
}
int
control(private_t *pri, pid_t pid)
{
const pstatus_t *Psp;
const lwpstatus_t *Lsp;
pid_t childpid = 0;
long flags;
int rc;
(void) mutex_lock(&gps->fork_lock);
while (gps->fork_pid != 0)
(void) cond_wait(&gps->fork_cv, &gps->fork_lock);
gps->fork_pid = getpid();
if ((childpid = fork()) == -1) {
(void) printf("%s\t*** Cannot fork() to control process #%d\n",
pri->pname, (int)pid);
Flush();
gps->fork_pid = 0;
(void) cond_broadcast(&gps->fork_cv);
(void) mutex_unlock(&gps->fork_lock);
release(pri, pid);
return (FALSE);
}
if (childpid != 0) {
while (gps->fork_pid != childpid)
(void) cond_wait(&gps->fork_cv, &gps->fork_lock);
gps->fork_pid = 0;
(void) cond_broadcast(&gps->fork_cv);
(void) mutex_unlock(&gps->fork_lock);
return (FALSE);
}
childpid = getpid();
descendent = TRUE;
exit_called = FALSE;
Pfree(Proc);
(void) mutex_lock(&gps->fork_lock);
if ((Proc = Pgrab(pid, PGRAB_RETAIN, &rc)) == NULL) {
(void) fprintf(stderr,
"%s: cannot control child process, pid# %d: %s\n",
command, (int)pid, Pgrab_error(rc));
gps->fork_pid = childpid;
(void) cond_broadcast(&gps->fork_cv);
(void) mutex_unlock(&gps->fork_lock);
exit(2);
}
per_proc_init();
procadd(pid, NULL);
gps->fork_pid = childpid;
(void) cond_broadcast(&gps->fork_cv);
(void) mutex_unlock(&gps->fork_lock);
(void) Pwait(Proc, MILLISEC);
if (Rdb_agent != NULL)
Rdb_agent = Prd_agent(Proc);
Psp = Pstatus(Proc);
Lsp = &Psp->pr_lwp;
pri->lwpstat = Lsp;
data_model = Psp->pr_dmodel;
make_pname(pri, 0);
pri->syslast = Psp->pr_stime;
pri->usrlast = Psp->pr_utime;
flags = PR_FORK | PR_ASYNC;
if (Dynpat != NULL)
flags |= PR_BPTADJ;
(void) Psetflags(Proc, flags);
return (TRUE);
}
int
grabit(private_t *pri, proc_set_t *set)
{
const pstatus_t *Psp;
const lwpstatus_t *Lsp;
int gcode;
if ((Proc = Pgrab(set->pid, Fflag, &gcode)) == NULL) {
(void) fprintf(stderr, "%s: %s: %d\n",
command, Pgrab_error(gcode), (int)set->pid);
pri->lwpstat = NULL;
return (FALSE);
}
Psp = Pstatus(Proc);
Lsp = &Psp->pr_lwp;
pri->lwpstat = Lsp;
make_pname(pri, 0);
data_model = Psp->pr_dmodel;
pri->syslast = Psp->pr_stime;
pri->usrlast = Psp->pr_utime;
if (fflag || Dynpat != NULL)
(void) Psetflags(Proc, PR_FORK);
else
(void) Punsetflags(Proc, PR_FORK);
procadd(set->pid, set->lwps);
show_cred(pri, TRUE, FALSE);
return (TRUE);
}
void
release(private_t *pri, pid_t pid)
{
int fd;
char ctlname[100];
long ctl[2];
ctl[0] = PCSET;
ctl[1] = PR_RLC;
(void) sprintf(ctlname, "/proc/%d/ctl", (int)pid);
if ((fd = open(ctlname, O_WRONLY)) < 0 ||
write(fd, (char *)ctl, sizeof (ctl)) < 0) {
perror("release()");
(void) printf(
"%s\t*** Cannot release child process, pid# %d\n",
pri->pname, (int)pid);
Flush();
}
if (fd >= 0)
(void) close(fd);
}
void
intr(int sig)
{
if (sig == SIGUSR1) {
sigusr1 = TRUE;
} else if (sig == SIGUSR2) {
void *value;
private_t *pri;
struct ps_lwphandle *Lwp;
if (thr_getspecific(private_key, &value) == 0 &&
(pri = value) != NULL &&
(Lwp = pri->Lwp) != NULL)
(void) Lstop(Lwp, MILLISEC / 10);
} else {
interrupt = sig;
}
}
void
errmsg(const char *s, const char *q)
{
char msg[512];
if (s || q) {
msg[0] = '\0';
if (command) {
(void) strcpy(msg, command);
(void) strcat(msg, ": ");
}
if (s)
(void) strcat(msg, s);
if (q)
(void) strcat(msg, q);
(void) strcat(msg, "\n");
(void) write(2, msg, (size_t)strlen(msg));
}
}
void
abend(const char *s, const char *q)
{
(void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL);
if (Proc) {
Flush();
errmsg(s, q);
clear_breakpoints();
(void) Punsetflags(Proc, PR_ASYNC);
Prelease(Proc, created? PRELEASE_KILL : PRELEASE_CLEAR);
procdel();
(void) wait4all();
} else {
errmsg(s, q);
}
exit(2);
}
void *
my_realloc(void *buf, size_t size, const char *msg)
{
if ((buf = realloc(buf, size)) == NULL) {
if (msg != NULL)
abend("cannot allocate ", msg);
else
abend("memory allocation failure", NULL);
}
return (buf);
}
void *
my_calloc(size_t nelem, size_t elsize, const char *msg)
{
void *buf = NULL;
if ((buf = calloc(nelem, elsize)) == NULL) {
if (msg != NULL)
abend("cannot allocate ", msg);
else
abend("memory allocation failure", NULL);
}
return (buf);
}
void *
my_malloc(size_t size, const char *msg)
{
return (my_realloc(NULL, size, msg));
}
int
wait4all()
{
int i;
pid_t pid;
int rc = 0;
int status;
for (i = 0; i < 10; i++) {
while ((pid = wait(&status)) != -1) {
if (pid == created) {
if (WIFEXITED(status))
rc = WEXITSTATUS(status);
else
rc |= 0x80;
}
}
if (errno != EINTR && errno != ERESTART)
break;
}
if (i >= 10)
rc = 2;
return (rc);
}
void
letgo(private_t *pri)
{
(void) printf("%s\t*** process otherwise traced, releasing ...\n",
pri->pname);
}
int
is_empty(const uint32_t *sp,
size_t n)
{
if (n) {
do {
if (*sp++)
return (FALSE);
} while (--n);
}
return (TRUE);
}
void
or_set(uint32_t *sp1, const uint32_t *sp2, size_t n)
{
if (n) {
do {
*sp1++ |= *sp2++;
} while (--n);
}
}