/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ramdata.h" #include "systable.h" #include "print.h" #include "proto.h" /* * Actions to take when process stops. */ /* * Function prototypes for static routines in this module. */ int stopsig(private_t *); void showpaths(private_t *, const struct systable *); void showargs(private_t *, int); void dumpargs(private_t *, long, const char *); /* * Report an lwp to be sleeping (if true). */ void report_sleeping(private_t *pri, int dotrace) { const lwpstatus_t *Lsp = pri->lwpstat; int sys = Lsp->pr_syscall; if (!prismember(&trace, sys) || !dotrace || !(Lsp->pr_flags & (PR_ASLEEP|PR_VFORKP))) { /* Make sure we catch sysexit even if we're not tracing it. */ (void) Psysexit(Proc, sys, TRUE); return; } pri->length = 0; pri->Errno = 0; pri->ErrPriv = PRIV_NONE; pri->Rval1 = pri->Rval2 = 0; (void) sysentry(pri, dotrace); make_pname(pri, 0); putpname(pri); timestamp(pri); pri->length += printf("%s", pri->sys_string); pri->sys_leng = 0; *pri->sys_string = '\0'; pri->length >>= 3; if (Lsp->pr_flags & PR_VFORKP) pri->length += 2; if (pri->length >= 4) (void) fputc(' ', stdout); for (; pri->length < 4; pri->length++) (void) fputc('\t', stdout); if (Lsp->pr_flags & PR_VFORKP) (void) fputs("(waiting for child to exit()/exec()...)\n", stdout); else (void) fputs("(sleeping...)\n", stdout); pri->length = 0; if (prismember(&verbose, sys)) { int raw = prismember(&rawout, sys); pri->Errno = 1; expound(pri, 0, raw); pri->Errno = 0; } Flush(); } /* * requested() gets called for these reasons: * flag == JOBSIG: report nothing; change state to JOBSTOP * flag == JOBSTOP: report "Continued ..." * default: report sleeping system call * * It returns a new flag: JOBSTOP or SLEEPING or 0. */ int requested(private_t *pri, int flag, int dotrace) { const lwpstatus_t *Lsp = pri->lwpstat; int sig = Lsp->pr_cursig; int newflag = 0; switch (flag) { case JOBSIG: return (JOBSTOP); case JOBSTOP: if (dotrace && !cflag && prismember(&signals, sig)) { pri->length = 0; putpname(pri); timestamp(pri); (void) printf(" Continued with signal #%d, %s", sig, signame(pri, sig)); if (Lsp->pr_action.sa_handler == SIG_DFL) (void) printf(" [default]"); else if (Lsp->pr_action.sa_handler == SIG_IGN) (void) printf(" [ignored]"); else (void) printf(" [caught]"); (void) fputc('\n', stdout); Flush(); } newflag = 0; break; default: newflag = SLEEPING; if (!cflag) report_sleeping(pri, dotrace); break; } return (newflag); } int jobcontrol(private_t *pri, int dotrace) { const lwpstatus_t *Lsp = pri->lwpstat; int sig = stopsig(pri); if (sig == 0) return (0); if (dotrace && !cflag && /* not just counting */ prismember(&signals, sig)) { /* tracing this signal */ int sys; pri->length = 0; putpname(pri); timestamp(pri); (void) printf(" Stopped by signal #%d, %s", sig, signame(pri, sig)); if ((Lsp->pr_flags & PR_ASLEEP) && (sys = Lsp->pr_syscall) > 0 && sys <= PRMAXSYS) (void) printf(", in %s()", sysname(pri, sys, getsubcode(pri))); (void) fputc('\n', stdout); Flush(); } return (JOBSTOP); } /* * Return the signal the process stopped on iff process is already stopped on * PR_JOBCONTROL or is stopped on PR_SIGNALLED or PR_REQUESTED with a current * signal that will cause a JOBCONTROL stop when the process is set running. */ int stopsig(private_t *pri) { const lwpstatus_t *Lsp = pri->lwpstat; int sig = 0; if (Lsp->pr_flags & PR_STOPPED) { switch (Lsp->pr_why) { case PR_JOBCONTROL: sig = Lsp->pr_what; if (sig < 0 || sig > PRMAXSIG) sig = 0; break; case PR_SIGNALLED: case PR_REQUESTED: if (Lsp->pr_action.sa_handler == SIG_DFL) { switch (Lsp->pr_cursig) { case SIGSTOP: sig = SIGSTOP; break; case SIGTSTP: case SIGTTIN: case SIGTTOU: if (!(Lsp->pr_flags & PR_ORPHAN)) sig = Lsp->pr_cursig; break; } } break; } } return (sig); } int signalled(private_t *pri, int flag, int dotrace) { const lwpstatus_t *Lsp = pri->lwpstat; int sig = Lsp->pr_what; if (sig <= 0 || sig > PRMAXSIG) /* check bounds */ return (0); if (dotrace && cflag) { /* just counting */ (void) mutex_lock(&count_lock); Cp->sigcount[sig]++; (void) mutex_unlock(&count_lock); } if (sig == SIGCONT && (flag == JOBSIG || flag == JOBSTOP)) flag = requested(pri, JOBSTOP, dotrace); else if ((flag = jobcontrol(pri, dotrace)) == 0 && !cflag && dotrace && prismember(&signals, sig)) { int sys; pri->length = 0; putpname(pri); timestamp(pri); (void) printf(" Received signal #%d, %s", sig, signame(pri, sig)); if ((Lsp->pr_flags & PR_ASLEEP) && (sys = Lsp->pr_syscall) > 0 && sys <= PRMAXSYS) (void) printf(", in %s()", sysname(pri, sys, getsubcode(pri))); if (Lsp->pr_action.sa_handler == SIG_DFL) (void) printf(" [default]"); else if (Lsp->pr_action.sa_handler == SIG_IGN) (void) printf(" [ignored]"); else (void) printf(" [caught]"); (void) fputc('\n', stdout); if (Lsp->pr_info.si_code != 0 || Lsp->pr_info.si_pid != 0) print_siginfo(pri, &Lsp->pr_info); Flush(); } if (flag == JOBSTOP) flag = JOBSIG; return (flag); } int faulted(private_t *pri, int dotrace) { const lwpstatus_t *Lsp = pri->lwpstat; int flt = Lsp->pr_what; if ((uint_t)flt > PRMAXFAULT || !prismember(&faults, flt) || !dotrace) return (0); (void) mutex_lock(&count_lock); Cp->fltcount[flt]++; (void) mutex_unlock(&count_lock); if (cflag) /* just counting */ return (1); pri->length = 0; putpname(pri); timestamp(pri); (void) printf(" Incurred fault #%d, %s %%pc = 0x%.8lX", flt, proc_fltname(flt, pri->flt_name, sizeof (pri->flt_name)), (long)Lsp->pr_reg[R_PC]); if (flt == FLTPAGE) (void) printf(" addr = 0x%.8lX", (long)Lsp->pr_info.si_addr); (void) fputc('\n', stdout); if (Lsp->pr_info.si_signo != 0) print_siginfo(pri, &Lsp->pr_info); Flush(); return (1); } /* * Set up pri->sys_nargs and pri->sys_args[] (syscall args). */ void setupsysargs(private_t *pri, int what) { const lwpstatus_t *Lsp = pri->lwpstat; int nargs; int i; #if sparc /* determine whether syscall is indirect */ pri->sys_indirect = (Lsp->pr_reg[R_G1] == SYS_syscall)? 1 : 0; #else pri->sys_indirect = 0; #endif (void) memset(pri->sys_args, 0, sizeof (pri->sys_args)); if (what != Lsp->pr_syscall) { /* assertion */ (void) printf("%s\t*** Inconsistent syscall: %d vs %d ***\n", pri->pname, what, Lsp->pr_syscall); } nargs = Lsp->pr_nsysarg; for (i = 0; i < nargs && i < sizeof (pri->sys_args) / sizeof (pri->sys_args[0]); i++) pri->sys_args[i] = Lsp->pr_sysarg[i]; pri->sys_nargs = nargs; } #define ISREAD(code) \ ((code) == SYS_read || (code) == SYS_pread || \ (code) == SYS_pread64 || (code) == SYS_readv || \ (code) == SYS_recv || (code) == SYS_recvfrom) #define ISWRITE(code) \ ((code) == SYS_write || (code) == SYS_pwrite || \ (code) == SYS_pwrite64 || (code) == SYS_writev || \ (code) == SYS_send || (code) == SYS_sendto) /* * Return TRUE iff syscall is being traced. */ int sysentry(private_t *pri, int dotrace) { pid_t pid = Pstatus(Proc)->pr_pid; const lwpstatus_t *Lsp = pri->lwpstat; long arg; int nargs; int i; int x; int len; char *s; const struct systable *stp; int what = Lsp->pr_what; int subcode; int istraced; int raw; /* for reporting sleeping system calls */ if (what == 0 && (Lsp->pr_flags & (PR_ASLEEP|PR_VFORKP))) what = Lsp->pr_syscall; /* protect ourself from operating system error */ if (what <= 0 || what > PRMAXSYS) what = 0; /* * Set up the system call arguments (pri->sys_nargs & pri->sys_args[]). */ setupsysargs(pri, what); nargs = pri->sys_nargs; /* get systable entry for this syscall */ subcode = getsubcode(pri); stp = subsys(what, subcode); if (nargs > stp->nargs) nargs = stp->nargs; pri->sys_nargs = nargs; /* fetch and remember first argument if it's a string */ pri->sys_valid = FALSE; if (nargs > 0 && stp->arg[0] == STG) { long offset; uint32_t offset32; /* * Special case for exit from exec(). * The address in pri->sys_args[0] refers to the old process * image. We must fetch the string from the new image. */ if (Lsp->pr_why == PR_SYSEXIT && (Lsp->pr_what == SYS_execve || Lsp->pr_what == SYS_exec)) { psinfo_t psinfo; long argv; auxv_t auxv[32]; int naux; offset = 0; naux = proc_get_auxv(pid, auxv, 32); for (i = 0; i < naux; i++) { if (auxv[i].a_type == AT_SUN_EXECNAME) { offset = (long)auxv[i].a_un.a_ptr; break; } } if (offset == 0 && proc_get_psinfo(pid, &psinfo) == 0) { argv = (long)psinfo.pr_argv; if (data_model == PR_MODEL_LP64) (void) Pread(Proc, &offset, sizeof (offset), argv); else { offset32 = 0; (void) Pread(Proc, &offset32, sizeof (offset32), argv); offset = offset32; } } } else { offset = pri->sys_args[0]; } if ((s = fetchstring(pri, offset, PATH_MAX)) != NULL) { pri->sys_valid = TRUE; len = strlen(s); /* reallocate if necessary */ while (len >= pri->sys_psize) { free(pri->sys_path); pri->sys_path = my_malloc(pri->sys_psize *= 2, "pathname buffer"); } (void) strcpy(pri->sys_path, s); /* remember pathname */ } } istraced = dotrace && prismember(&trace, what); raw = prismember(&rawout, what); /* force tracing of read/write buffer dump syscalls */ if (!istraced && nargs > 2) { int fdp1 = (int)pri->sys_args[0] + 1; if (ISREAD(what)) { if (prismember(&readfd, fdp1)) istraced = TRUE; } else if (ISWRITE(what)) { if (prismember(&writefd, fdp1)) istraced = TRUE; } } pri->sys_leng = 0; if (cflag || !istraced) /* just counting */ *pri->sys_string = 0; else { int argprinted = FALSE; const char *name; name = sysname(pri, what, raw? -1 : subcode); grow(pri, strlen(name) + 1); pri->sys_leng = snprintf(pri->sys_string, pri->sys_ssize, "%s(", name); for (i = 0; i < nargs; i++) { arg = pri->sys_args[i]; x = stp->arg[i]; if (x == STG && !raw && i == 0 && pri->sys_valid) { /* already fetched */ escape_string(pri, pri->sys_path); argprinted = TRUE; } else if (x != HID || raw) { if (argprinted) outstring(pri, ", "); if (x == LLO) (*Print[x])(pri, raw, arg, pri->sys_args[++i]); else (*Print[x])(pri, raw, arg); /* * if nothing printed, then don't print ", " */ if (x == NOV) argprinted = FALSE; else argprinted = TRUE; } } outstring(pri, ")"); } return (istraced); } #undef ISREAD #undef ISWRITE /* * sysexit() returns non-zero if anything was printed. */ int sysexit(private_t *pri, int dotrace) { const lwpstatus_t *Lsp = pri->lwpstat; int what = Lsp->pr_what; struct syscount *scp; const struct systable *stp; int subcode; int istraced; int raw; /* protect ourself from operating system error */ if (what <= 0 || what > PRMAXSYS) return (0); /* * If we aren't supposed to be tracing this one, then * delete it from the traced signal set. We got here * because the process was sleeping in an untraced syscall. */ if (!prismember(&traceeven, what)) { (void) Psysexit(Proc, what, FALSE); return (0); } /* pick up registers & set pri->Errno before anything else */ pri->Errno = Lsp->pr_errno; pri->ErrPriv = Lsp->pr_errpriv; pri->Rval1 = Lsp->pr_rval1; pri->Rval2 = Lsp->pr_rval2; switch (what) { case SYS_exit: /* these are traced on entry */ case SYS_lwp_exit: case SYS_evtrapret: case SYS_context: istraced = dotrace && prismember(&trace, what); break; case SYS_exec: /* these are normally traced on entry */ case SYS_execve: istraced = dotrace && prismember(&trace, what); if (pri->exec_string && *pri->exec_string) { if (!cflag && istraced) { /* print exec() string now */ if (pri->exec_pname[0] != '\0') (void) fputs(pri->exec_pname, stdout); timestamp(pri); (void) fputs(pri->exec_string, stdout); } pri->exec_pname[0] = '\0'; pri->exec_string[0] = '\0'; break; } /* FALLTHROUGH */ default: /* we called sysentry() in main() for these */ if (what == SYS_open || what == SYS_open64) istraced = dotrace && prismember(&trace, what); else istraced = sysentry(pri, dotrace) && dotrace; pri->length = 0; if (!cflag && istraced) { putpname(pri); timestamp(pri); pri->length += printf("%s", pri->sys_string); } pri->sys_leng = 0; *pri->sys_string = '\0'; break; } /* get systable entry for this syscall */ subcode = getsubcode(pri); stp = subsys(what, subcode); if (cflag && istraced) { (void) mutex_lock(&count_lock); scp = Cp->syscount[what]; if (what == SYS_forksys && subcode >= 3) scp += subcode - 3; else if (subcode != -1 && (what != SYS_open && what != SYS_open64 && what != SYS_lwp_create)) scp += 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); } raw = prismember(&rawout, what); if (!cflag && istraced) { if ((what == SYS_forkall || what == SYS_vfork || what == SYS_fork1 || what == SYS_forksys) && pri->Errno == 0 && pri->Rval2 != 0) { pri->length &= ~07; if (strlen(sysname(pri, what, raw? -1 : subcode)) < 6) { (void) fputc('\t', stdout); pri->length += 8; } pri->length += 7 + printf("\t(returning as child ...)"); } if (what == SYS_lwp_create && pri->Errno == 0 && pri->Rval1 == 0) { pri->length &= ~07; pri->length += 7 + printf("\t(returning as new lwp ...)"); } if (pri->Errno != 0 || (what != SYS_exec && what != SYS_execve)) { /* prepare to print the return code */ pri->length >>= 3; if (pri->length >= 6) (void) fputc(' ', stdout); for (; pri->length < 6; pri->length++) (void) fputc('\t', stdout); } } pri->length = 0; if (pri->Errno != 0) { /* error in syscall */ if (istraced) { if (cflag) scp->error++; else { const char *ename = errname(pri->Errno); const char *privname; (void) printf("Err#%d", pri->Errno); if (ename != NULL) { (void) fputc(' ', stdout); (void) fputs(ename, stdout); } switch (pri->ErrPriv) { case PRIV_NONE: privname = NULL; break; case PRIV_ALL: privname = "ALL"; break; case PRIV_MULTIPLE: privname = "MULTIPLE"; break; case PRIV_ALLZONE: privname = "ZONE"; break; default: privname = priv_getbynum(pri->ErrPriv); break; } if (privname != NULL) (void) printf(" [%s]", privname); (void) fputc('\n', stdout); } } } else { /* show arguments on successful exec */ if (what == SYS_exec || what == SYS_execve) { if (!cflag && istraced) showargs(pri, raw); } else if (!cflag && istraced) { const char *fmt = NULL; long rv1 = pri->Rval1; long rv2 = pri->Rval2; #ifdef _LP64 /* * 32-bit system calls return 32-bit values. We * later mask out the upper bits if we want to * print these as unsigned values. */ if (data_model == PR_MODEL_ILP32) { rv1 = (int)rv1; rv2 = (int)rv2; } #endif switch (what) { case SYS_llseek: rv1 &= 0xffffffff; rv2 &= 0xffffffff; #ifdef _LONG_LONG_LTOH /* first long of a longlong is the low order */ if (rv2 != 0) { long temp = rv1; fmt = "= 0x%lX%.8lX"; rv1 = rv2; rv2 = temp; break; } #else /* the other way around */ if (rv1 != 0) { fmt = "= 0x%lX%.8lX"; break; } rv1 = rv2; /* ugly */ #endif /* FALLTHROUGH */ case SYS_lseek: case SYS_ulimit: if (rv1 & 0xff000000) { #ifdef _LP64 if (data_model == PR_MODEL_ILP32) rv1 &= 0xffffffff; #endif fmt = "= 0x%.8lX"; } break; case SYS_sigtimedwait: if (raw) /* EMPTY */; else if ((fmt = rawsigname(pri, rv1)) != NULL) { rv1 = (long)fmt; /* filthy */ fmt = "= %s"; } break; case SYS_port: #ifdef _LP64 if (data_model == PR_MODEL_LP64) { rv2 = rv1 & 0xffffffff; rv1 = rv1 >> 32; } #endif break; } if (fmt == NULL) { switch (stp->rval[0]) { case HEX: #ifdef _LP64 if (data_model == PR_MODEL_ILP32) rv1 &= 0xffffffff; #endif fmt = "= 0x%.8lX"; break; case HHX: #ifdef _LP64 if (data_model == PR_MODEL_ILP32) rv1 &= 0xffffffff; #endif fmt = "= 0x%.4lX"; break; case OCT: #ifdef _LP64 if (data_model == PR_MODEL_ILP32) rv1 &= 0xffffffff; #endif fmt = "= %#lo"; break; case UNS: #ifdef _LP64 if (data_model == PR_MODEL_ILP32) rv1 &= 0xffffffff; #endif fmt = "= %lu"; break; default: fmt = "= %ld"; break; } } (void) printf(fmt, rv1, rv2); switch (stp->rval[1]) { case NOV: fmt = NULL; break; case HEX: #ifdef _LP64 if (data_model == PR_MODEL_ILP32) rv2 &= 0xffffffff; #endif fmt = " [0x%.8lX]"; break; case HHX: #ifdef _LP64 if (data_model == PR_MODEL_ILP32) rv2 &= 0xffffffff; #endif fmt = " [0x%.4lX]"; break; case OCT: #ifdef _LP64 if (data_model == PR_MODEL_ILP32) rv2 &= 0xffffffff; #endif fmt = " [%#lo]"; break; case UNS: #ifdef _LP64 if (data_model == PR_MODEL_ILP32) rv2 &= 0xffffffff; #endif fmt = " [%lu]"; break; default: fmt = " [%ld]"; break; } if (fmt != NULL) (void) printf(fmt, rv2); (void) fputc('\n', stdout); } if (what == SYS_forkall || what == SYS_vfork || what == SYS_fork1 || what == SYS_forksys) { if (pri->Rval2 == 0) /* child was created */ pri->child = pri->Rval1; else if (cflag && istraced) /* this is the child */ scp->count--; } if (what == SYS_lwp_create && pri->Rval1 == 0 && cflag && istraced) /* this is the created lwp */ scp->count--; } #define ISREAD(code) \ ((code) == SYS_read || (code) == SYS_pread || (code) == SYS_pread64 || \ (code) == SYS_recv || (code) == SYS_recvfrom) #define ISWRITE(code) \ ((code) == SYS_write || (code) == SYS_pwrite || \ (code) == SYS_pwrite64 || (code) == SYS_send || (code) == SYS_sendto) if (!cflag && istraced) { int fdp1 = (int)pri->sys_args[0] + 1; /* filedescriptor + 1 */ if (raw) { if (what != SYS_exec && what != SYS_execve) showpaths(pri, stp); if (ISREAD(what) || ISWRITE(what)) { if (pri->iob_buf[0] != '\0') (void) printf("%s 0x%.8lX: %s\n", pri->pname, pri->sys_args[1], pri->iob_buf); } } /* * Show buffer contents for read()/pread() or write()/pwrite(). * IOBSIZE bytes have already been shown; * don't show them again unless there's more. */ if ((ISREAD(what) && pri->Errno == 0 && prismember(&readfd, fdp1)) || (ISWRITE(what) && prismember(&writefd, fdp1))) { long nb = ISWRITE(what) ? pri->sys_args[2] : pri->Rval1; if (nb > IOBSIZE) { /* enter region of lengthy output */ if (nb > MYBUFSIZ / 4) Eserialize(); showbuffer(pri, pri->sys_args[1], nb); /* exit region of lengthy output */ if (nb > MYBUFSIZ / 4) Xserialize(); } } #undef ISREAD #undef ISWRITE /* * Do verbose interpretation if requested. * If buffer contents for read or write have been requested and * this is a readv() or writev(), force verbose interpretation. */ if (prismember(&verbose, what) || ((what == SYS_readv || what == SYS_recvmsg) && pri->Errno == 0 && prismember(&readfd, fdp1)) || ((what == SYS_writev || what == SYS_sendfilev || what == SYS_sendmsg) && prismember(&writefd, fdp1))) expound(pri, pri->Rval1, raw); } return (!cflag && istraced); } void showpaths(private_t *pri, const struct systable *stp) { int i; for (i = 0; i < pri->sys_nargs; i++) { if ((stp->arg[i] == STG) || (stp->arg[i] == RST && !pri->Errno) || (stp->arg[i] == RLK && !pri->Errno && pri->Rval1 > 0)) { long addr = pri->sys_args[i]; int maxleng = (stp->arg[i] == RLK)? (int)pri->Rval1 : PATH_MAX; char *s; if (i == 0 && pri->sys_valid) /* already fetched */ s = pri->sys_path; else s = fetchstring(pri, addr, maxleng > PATH_MAX ? PATH_MAX : maxleng); if (s != (char *)NULL) (void) printf("%s 0x%.8lX: \"%s\"\n", pri->pname, addr, s); } } } /* * Display arguments to successful exec(). */ void showargs(private_t *pri, int raw) { const lwpstatus_t *Lsp = pri->lwpstat; int nargs; long ap; int ptrsize; int fail; pri->length = 0; ptrsize = (data_model == PR_MODEL_LP64)? 8 : 4; #if defined(__i386) || defined(__amd64) /* XX64 */ ap = (long)Lsp->pr_reg[R_SP]; fail = (Pread(Proc, &nargs, sizeof (nargs), ap) != sizeof (nargs)); ap += ptrsize; #endif /* i386 */ #if sparc if (data_model == PR_MODEL_LP64) { int64_t xnargs; ap = (long)(Lsp->pr_reg[R_SP]) + 16 * sizeof (int64_t) + STACK_BIAS; fail = (Pread(Proc, &xnargs, sizeof (xnargs), ap) != sizeof (xnargs)); nargs = (int)xnargs; } else { ap = (long)(Lsp->pr_reg[R_SP]) + 16 * sizeof (int32_t); fail = (Pread(Proc, &nargs, sizeof (nargs), ap) != sizeof (nargs)); } ap += ptrsize; #endif /* sparc */ if (fail) { (void) printf("\n%s\t*** Bad argument list? ***\n", pri->pname); return; } (void) printf(" argc = %d\n", nargs); if (raw) showpaths(pri, &systable[SYS_exec]); show_cred(pri, FALSE); if (aflag || eflag) { /* dump args or environment */ /* enter region of (potentially) lengthy output */ Eserialize(); if (aflag) /* dump the argument list */ dumpargs(pri, ap, "argv:"); ap += (nargs+1) * ptrsize; if (eflag) /* dump the environment */ dumpargs(pri, ap, "envp:"); /* exit region of lengthy output */ Xserialize(); } } void dumpargs(private_t *pri, long ap, const char *str) { char *string; unsigned int leng = 0; int ptrsize; long arg = 0; char *argaddr; char badaddr[32]; if (interrupt) return; #ifdef _LP64 if (data_model == PR_MODEL_LP64) { argaddr = (char *)&arg; ptrsize = 8; } else { #if defined(_LITTLE_ENDIAN) argaddr = (char *)&arg; #else argaddr = (char *)&arg + 4; #endif ptrsize = 4; } #else argaddr = (char *)&arg; ptrsize = 4; #endif putpname(pri); (void) fputc(' ', stdout); (void) fputs(str, stdout); leng += 1 + strlen(str); while (!interrupt) { if (Pread(Proc, argaddr, ptrsize, ap) != ptrsize) { (void) printf("\n%s\t*** Bad argument list? ***\n", pri->pname); return; } ap += ptrsize; if (arg == 0) break; string = fetchstring(pri, arg, PATH_MAX); if (string == NULL) { (void) sprintf(badaddr, "BadAddress:0x%.8lX", arg); string = badaddr; } if ((leng += strlen(string)) < 63) { (void) fputc(' ', stdout); leng++; } else { (void) fputc('\n', stdout); leng = 0; putpname(pri); (void) fputs(" ", stdout); leng += 2 + strlen(string); } (void) fputs(string, stdout); } (void) fputc('\n', stdout); } /* * Display contents of read() or write() buffer. */ void showbuffer(private_t *pri, long offset, long count) { char buffer[320]; int nbytes; char *buf; int n; while (count > 0 && !interrupt) { nbytes = (count < sizeof (buffer))? count : sizeof (buffer); if ((nbytes = Pread(Proc, buffer, nbytes, offset)) <= 0) break; count -= nbytes; offset += nbytes; buf = buffer; while (nbytes > 0 && !interrupt) { char obuf[65]; n = (nbytes < 32)? nbytes : 32; showbytes(buf, n, obuf); putpname(pri); (void) fputs(" ", stdout); (void) fputs(obuf, stdout); (void) fputc('\n', stdout); nbytes -= n; buf += n; } } } void showbytes(const char *buf, int n, char *obuf) { int c; while (--n >= 0) { int c1 = '\\'; int c2; switch (c = (*buf++ & 0xff)) { case '\0': c2 = '0'; break; case '\b': c2 = 'b'; break; case '\t': c2 = 't'; break; case '\n': c2 = 'n'; break; case '\v': c2 = 'v'; break; case '\f': c2 = 'f'; break; case '\r': c2 = 'r'; break; default: if (isprint(c)) { c1 = ' '; c2 = c; } else { c1 = c>>4; c1 += (c1 < 10)? '0' : 'A'-10; c2 = c&0xf; c2 += (c2 < 10)? '0' : 'A'-10; } break; } *obuf++ = (char)c1; *obuf++ = (char)c2; } *obuf = '\0'; }