1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <stdio.h>
30*0Sstevel@tonic-gate #include <stdlib.h>
31*0Sstevel@tonic-gate #include <unistd.h>
32*0Sstevel@tonic-gate #include <ctype.h>
33*0Sstevel@tonic-gate #include <fcntl.h>
34*0Sstevel@tonic-gate #include <strings.h>
35*0Sstevel@tonic-gate #include <dirent.h>
36*0Sstevel@tonic-gate #include <errno.h>
37*0Sstevel@tonic-gate #include <sys/types.h>
38*0Sstevel@tonic-gate #include <sys/int_fmtio.h>
39*0Sstevel@tonic-gate #include <libproc.h>
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate typedef struct look_arg {
42*0Sstevel@tonic-gate 	int pflags;
43*0Sstevel@tonic-gate 	const char *lwps;
44*0Sstevel@tonic-gate 	int count;
45*0Sstevel@tonic-gate } look_arg_t;
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate static	int	look(char *);
48*0Sstevel@tonic-gate static	int	lwplook(look_arg_t *, const lwpstatus_t *, const lwpsinfo_t *);
49*0Sstevel@tonic-gate static	char	*prflags(int);
50*0Sstevel@tonic-gate static	char	*prwhy(int);
51*0Sstevel@tonic-gate static	char	*prwhat(int, int);
52*0Sstevel@tonic-gate static	void	dumpregs(const prgregset_t, int);
53*0Sstevel@tonic-gate #if defined(__sparc) && defined(_ILP32)
54*0Sstevel@tonic-gate static	void	dumpregs_v8p(const prgregset_t, const prxregset_t *, int);
55*0Sstevel@tonic-gate #endif
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate static	char	*command;
58*0Sstevel@tonic-gate static	struct	ps_prochandle *Pr;
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate static	int	is64;	/* Is current process 64-bit? */
61*0Sstevel@tonic-gate static	int	rflag;	/* Show registers? */
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate #define	LWPFLAGS	\
64*0Sstevel@tonic-gate 	(PR_STOPPED|PR_ISTOP|PR_DSTOP|PR_ASLEEP|PR_PCINVAL|PR_STEP \
65*0Sstevel@tonic-gate 	|PR_ASLWP|PR_AGENT|PR_DETACH|PR_DAEMON)
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate #define	PROCFLAGS	\
68*0Sstevel@tonic-gate 	(PR_ISSYS|PR_VFORKP|PR_ORPHAN|PR_FORK|PR_RLC|PR_KLC|PR_ASYNC \
69*0Sstevel@tonic-gate 	|PR_BPTADJ|PR_MSACCT|PR_MSFORK|PR_PTRACE)
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate #define	ALLFLAGS	(LWPFLAGS|PROCFLAGS)
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate int
74*0Sstevel@tonic-gate main(int argc, char **argv)
75*0Sstevel@tonic-gate {
76*0Sstevel@tonic-gate 	int rc = 0;
77*0Sstevel@tonic-gate 	int errflg = 0;
78*0Sstevel@tonic-gate 	int opt;
79*0Sstevel@tonic-gate 	struct rlimit rlim;
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate 	if ((command = strrchr(argv[0], '/')) != NULL)
82*0Sstevel@tonic-gate 		command++;
83*0Sstevel@tonic-gate 	else
84*0Sstevel@tonic-gate 		command = argv[0];
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate 	/* options */
87*0Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "r")) != EOF) {
88*0Sstevel@tonic-gate 		switch (opt) {
89*0Sstevel@tonic-gate 		case 'r':		/* show registers */
90*0Sstevel@tonic-gate 			rflag = 1;
91*0Sstevel@tonic-gate 			break;
92*0Sstevel@tonic-gate 		default:
93*0Sstevel@tonic-gate 			errflg = 1;
94*0Sstevel@tonic-gate 			break;
95*0Sstevel@tonic-gate 		}
96*0Sstevel@tonic-gate 	}
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate 	argc -= optind;
99*0Sstevel@tonic-gate 	argv += optind;
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 	if (errflg || argc <= 0) {
102*0Sstevel@tonic-gate 		(void) fprintf(stderr,
103*0Sstevel@tonic-gate 		    "usage:\t%s [-r] { pid | core }[/lwps] ...\n", command);
104*0Sstevel@tonic-gate 		(void) fprintf(stderr, "  (report process status flags)\n");
105*0Sstevel@tonic-gate 		(void) fprintf(stderr, "  -r : report registers\n");
106*0Sstevel@tonic-gate 		return (2);
107*0Sstevel@tonic-gate 	}
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 	/*
110*0Sstevel@tonic-gate 	 * Make sure we'll have enough file descriptors to handle a target
111*0Sstevel@tonic-gate 	 * that has many many mappings.
112*0Sstevel@tonic-gate 	 */
113*0Sstevel@tonic-gate 	if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
114*0Sstevel@tonic-gate 		rlim.rlim_cur = rlim.rlim_max;
115*0Sstevel@tonic-gate 		(void) setrlimit(RLIMIT_NOFILE, &rlim);
116*0Sstevel@tonic-gate 	}
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate 	while (argc-- > 0)
119*0Sstevel@tonic-gate 		rc += look(*argv++);
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate 	return (rc);
122*0Sstevel@tonic-gate }
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate static int
125*0Sstevel@tonic-gate look(char *arg)
126*0Sstevel@tonic-gate {
127*0Sstevel@tonic-gate 	int gcode;
128*0Sstevel@tonic-gate 	int gcode2;
129*0Sstevel@tonic-gate 	pstatus_t pstatus;
130*0Sstevel@tonic-gate 	psinfo_t psinfo;
131*0Sstevel@tonic-gate 	int flags;
132*0Sstevel@tonic-gate 	sigset_t sigmask;
133*0Sstevel@tonic-gate 	fltset_t fltmask;
134*0Sstevel@tonic-gate 	sysset_t entryset;
135*0Sstevel@tonic-gate 	sysset_t exitset;
136*0Sstevel@tonic-gate 	uint32_t sigtrace, sigtrace2, fltbits;
137*0Sstevel@tonic-gate 	uint32_t sigpend, sigpend2;
138*0Sstevel@tonic-gate 	uint32_t *bits;
139*0Sstevel@tonic-gate 	char buf[PRSIGBUFSZ];
140*0Sstevel@tonic-gate 	look_arg_t lookarg;
141*0Sstevel@tonic-gate 
142*0Sstevel@tonic-gate 	if ((Pr = proc_arg_xgrab(arg, NULL, PR_ARG_ANY,
143*0Sstevel@tonic-gate 	    PGRAB_RETAIN | PGRAB_FORCE | PGRAB_RDONLY | PGRAB_NOSTOP, &gcode,
144*0Sstevel@tonic-gate 	    &lookarg.lwps)) == NULL) {
145*0Sstevel@tonic-gate 		if (gcode == G_NOPROC &&
146*0Sstevel@tonic-gate 		    proc_arg_psinfo(arg, PR_ARG_PIDS, &psinfo, &gcode2) > 0 &&
147*0Sstevel@tonic-gate 		    psinfo.pr_nlwp == 0) {
148*0Sstevel@tonic-gate 			(void) printf("%d:\t<defunct>\n\n", (int)psinfo.pr_pid);
149*0Sstevel@tonic-gate 			return (0);
150*0Sstevel@tonic-gate 		}
151*0Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: cannot examine %s: %s\n",
152*0Sstevel@tonic-gate 			command, arg, Pgrab_error(gcode));
153*0Sstevel@tonic-gate 		return (1);
154*0Sstevel@tonic-gate 	}
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate 	(void) memcpy(&pstatus, Pstatus(Pr), sizeof (pstatus_t));
157*0Sstevel@tonic-gate 	(void) memcpy(&psinfo, Ppsinfo(Pr), sizeof (psinfo_t));
158*0Sstevel@tonic-gate 	proc_unctrl_psinfo(&psinfo);
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate 	if (psinfo.pr_nlwp == 0) {
161*0Sstevel@tonic-gate 		(void) printf("%d:\t<defunct>\n\n", (int)psinfo.pr_pid);
162*0Sstevel@tonic-gate 		Prelease(Pr, PRELEASE_RETAIN);
163*0Sstevel@tonic-gate 		return (0);
164*0Sstevel@tonic-gate 	}
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 	is64 = (pstatus.pr_dmodel == PR_MODEL_LP64);
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate 	sigmask = pstatus.pr_sigtrace;
169*0Sstevel@tonic-gate 	fltmask = pstatus.pr_flttrace;
170*0Sstevel@tonic-gate 	entryset = pstatus.pr_sysentry;
171*0Sstevel@tonic-gate 	exitset = pstatus.pr_sysexit;
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate 	if (Pstate(Pr) == PS_DEAD) {
174*0Sstevel@tonic-gate 		(void) printf("core '%s' of %d:\t%.70s\n",
175*0Sstevel@tonic-gate 		    arg, (int)psinfo.pr_pid, psinfo.pr_psargs);
176*0Sstevel@tonic-gate 	} else {
177*0Sstevel@tonic-gate 		(void) printf("%d:\t%.70s\n",
178*0Sstevel@tonic-gate 		    (int)psinfo.pr_pid, psinfo.pr_psargs);
179*0Sstevel@tonic-gate 	}
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 	(void) printf("\tdata model = %s", is64? "_LP64" : "_ILP32");
182*0Sstevel@tonic-gate 	if ((flags = (pstatus.pr_flags & PROCFLAGS)) != 0)
183*0Sstevel@tonic-gate 		(void) printf("  flags = %s", prflags(flags));
184*0Sstevel@tonic-gate 	(void) printf("\n");
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate 	fltbits = *((uint32_t *)&fltmask);
187*0Sstevel@tonic-gate 	if (fltbits)
188*0Sstevel@tonic-gate 		(void) printf("\tflttrace = 0x%.8x\n", fltbits);
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate 	sigtrace = *((uint32_t *)&sigmask);
191*0Sstevel@tonic-gate 	sigtrace2 = *((uint32_t *)&sigmask + 1);
192*0Sstevel@tonic-gate 	if (sigtrace | sigtrace2) {
193*0Sstevel@tonic-gate 		(void) printf("\tsigtrace = 0x%.8x 0x%.8x\n\t    %s\n",
194*0Sstevel@tonic-gate 		    sigtrace, sigtrace2,
195*0Sstevel@tonic-gate 		    proc_sigset2str(&sigmask, "|", 1, buf, sizeof (buf)));
196*0Sstevel@tonic-gate 	}
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate 	bits = ((uint32_t *)&entryset);
199*0Sstevel@tonic-gate 	if (bits[0] | bits[1] | bits[2] | bits[3] |
200*0Sstevel@tonic-gate 	    bits[4] | bits[5] | bits[6] | bits[7])
201*0Sstevel@tonic-gate 		(void) printf(
202*0Sstevel@tonic-gate 			"\tentryset = "
203*0Sstevel@tonic-gate 			"0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
204*0Sstevel@tonic-gate 			"\t           "
205*0Sstevel@tonic-gate 			"0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
206*0Sstevel@tonic-gate 			bits[0], bits[1], bits[2], bits[3],
207*0Sstevel@tonic-gate 			bits[4], bits[5], bits[6], bits[7]);
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	bits = ((uint32_t *)&exitset);
210*0Sstevel@tonic-gate 	if (bits[0] | bits[1] | bits[2] | bits[3] |
211*0Sstevel@tonic-gate 	    bits[4] | bits[5] | bits[6] | bits[7])
212*0Sstevel@tonic-gate 		(void) printf(
213*0Sstevel@tonic-gate 			"\texitset  = "
214*0Sstevel@tonic-gate 			"0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
215*0Sstevel@tonic-gate 			"\t           "
216*0Sstevel@tonic-gate 			"0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
217*0Sstevel@tonic-gate 			bits[0], bits[1], bits[2], bits[3],
218*0Sstevel@tonic-gate 			bits[4], bits[5], bits[6], bits[7]);
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 	sigpend  = *((uint32_t *)&pstatus.pr_sigpend);
221*0Sstevel@tonic-gate 	sigpend2 = *((uint32_t *)&pstatus.pr_sigpend + 1);
222*0Sstevel@tonic-gate 	if (sigpend | sigpend2)
223*0Sstevel@tonic-gate 		(void) printf("\tsigpend = 0x%.8x,0x%.8x\n",
224*0Sstevel@tonic-gate 			sigpend, sigpend2);
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate 	lookarg.pflags = pstatus.pr_flags;
227*0Sstevel@tonic-gate 	lookarg.count = 0;
228*0Sstevel@tonic-gate 	(void) Plwp_iter_all(Pr, (proc_lwp_all_f *)lwplook, &lookarg);
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 	if (lookarg.count == 0)
231*0Sstevel@tonic-gate 		(void) printf("No matching lwps found");
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate 	(void) printf("\n");
234*0Sstevel@tonic-gate 	Prelease(Pr, PRELEASE_RETAIN);
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate 	return (0);
237*0Sstevel@tonic-gate }
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate static int
240*0Sstevel@tonic-gate lwplook_zombie(const lwpsinfo_t *pip)
241*0Sstevel@tonic-gate {
242*0Sstevel@tonic-gate 	(void) printf(" /%d:\t<defunct>\n", (int)pip->pr_lwpid);
243*0Sstevel@tonic-gate 	return (0);
244*0Sstevel@tonic-gate }
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate static int
247*0Sstevel@tonic-gate lwplook(look_arg_t *arg, const lwpstatus_t *psp, const lwpsinfo_t *pip)
248*0Sstevel@tonic-gate {
249*0Sstevel@tonic-gate 	int flags;
250*0Sstevel@tonic-gate 	uint32_t sighold, sighold2;
251*0Sstevel@tonic-gate 	uint32_t sigpend, sigpend2;
252*0Sstevel@tonic-gate 	int cursig;
253*0Sstevel@tonic-gate 	char buf[32];
254*0Sstevel@tonic-gate 
255*0Sstevel@tonic-gate 	if (!proc_lwp_in_set(arg->lwps, pip->pr_lwpid))
256*0Sstevel@tonic-gate 		return (0);
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate 	arg->count++;
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate 	if (psp == NULL)
261*0Sstevel@tonic-gate 		return (lwplook_zombie(pip));
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 	/*
264*0Sstevel@tonic-gate 	 * PR_PCINVAL is just noise if the lwp is not stopped.
265*0Sstevel@tonic-gate 	 * Don't bother reporting it unless the lwp is stopped.
266*0Sstevel@tonic-gate 	 */
267*0Sstevel@tonic-gate 	flags = psp->pr_flags & LWPFLAGS;
268*0Sstevel@tonic-gate 	if (!(flags & PR_STOPPED))
269*0Sstevel@tonic-gate 		flags &= ~PR_PCINVAL;
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	(void) printf(" /%d:\tflags = %s", (int)psp->pr_lwpid, prflags(flags));
272*0Sstevel@tonic-gate 	if ((flags & PR_ASLEEP) || (psp->pr_syscall &&
273*0Sstevel@tonic-gate 	    !(arg->pflags & PR_ISSYS))) {
274*0Sstevel@tonic-gate 		if (flags & PR_ASLEEP) {
275*0Sstevel@tonic-gate 			if ((flags & ~PR_ASLEEP) != 0)
276*0Sstevel@tonic-gate 				(void) printf("|");
277*0Sstevel@tonic-gate 			(void) printf("ASLEEP");
278*0Sstevel@tonic-gate 		}
279*0Sstevel@tonic-gate 		if (psp->pr_syscall && !(arg->pflags & PR_ISSYS)) {
280*0Sstevel@tonic-gate 			uint_t i;
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate 			(void) printf("  %s(",
283*0Sstevel@tonic-gate 			    proc_sysname(psp->pr_syscall, buf, sizeof (buf)));
284*0Sstevel@tonic-gate 			for (i = 0; i < psp->pr_nsysarg; i++) {
285*0Sstevel@tonic-gate 				if (i != 0)
286*0Sstevel@tonic-gate 					(void) printf(",");
287*0Sstevel@tonic-gate 				(void) printf("0x%lx", psp->pr_sysarg[i]);
288*0Sstevel@tonic-gate 			}
289*0Sstevel@tonic-gate 			(void) printf(")");
290*0Sstevel@tonic-gate 		}
291*0Sstevel@tonic-gate 	}
292*0Sstevel@tonic-gate 	(void) printf("\n");
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 	if (flags & PR_STOPPED) {
295*0Sstevel@tonic-gate 		(void) printf("\twhy = %s", prwhy(psp->pr_why));
296*0Sstevel@tonic-gate 		if (psp->pr_why != PR_REQUESTED &&
297*0Sstevel@tonic-gate 		    psp->pr_why != PR_SUSPENDED)
298*0Sstevel@tonic-gate 			(void) printf("  what = %s",
299*0Sstevel@tonic-gate 				prwhat(psp->pr_why, psp->pr_what));
300*0Sstevel@tonic-gate 		(void) printf("\n");
301*0Sstevel@tonic-gate 	}
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate 	sighold  = *((uint32_t *)&psp->pr_lwphold);
304*0Sstevel@tonic-gate 	sighold2 = *((uint32_t *)&psp->pr_lwphold + 1);
305*0Sstevel@tonic-gate 	sigpend  = *((uint32_t *)&psp->pr_lwppend);
306*0Sstevel@tonic-gate 	sigpend2 = *((uint32_t *)&psp->pr_lwppend + 1);
307*0Sstevel@tonic-gate 	cursig   = psp->pr_cursig;
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 	if (sighold | sighold2 | sigpend | sigpend2 | cursig) {
310*0Sstevel@tonic-gate 		(void) printf("\t");
311*0Sstevel@tonic-gate 		if (sighold | sighold2) {
312*0Sstevel@tonic-gate 			(void) printf("sigmask = 0x%.8x,0x%.8x",
313*0Sstevel@tonic-gate 				sighold, sighold2);
314*0Sstevel@tonic-gate 			if (sigpend | sigpend2 | cursig)
315*0Sstevel@tonic-gate 				(void) printf("  ");
316*0Sstevel@tonic-gate 		}
317*0Sstevel@tonic-gate 		if (sigpend | sigpend2) {
318*0Sstevel@tonic-gate 			(void) printf("lwppend = 0x%.8x,0x%.8x",
319*0Sstevel@tonic-gate 				sigpend, sigpend2);
320*0Sstevel@tonic-gate 			if (cursig)
321*0Sstevel@tonic-gate 				(void) printf("  ");
322*0Sstevel@tonic-gate 		}
323*0Sstevel@tonic-gate 		if (cursig)
324*0Sstevel@tonic-gate 			(void) printf("cursig = %s",
325*0Sstevel@tonic-gate 			    proc_signame(cursig, buf, sizeof (buf)));
326*0Sstevel@tonic-gate 		(void) printf("\n");
327*0Sstevel@tonic-gate 	}
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 	if (rflag) {
330*0Sstevel@tonic-gate 		if (Pstate(Pr) == PS_DEAD || (arg->pflags & PR_STOPPED)) {
331*0Sstevel@tonic-gate #if defined(__sparc) && defined(_ILP32)
332*0Sstevel@tonic-gate 			/*
333*0Sstevel@tonic-gate 			 * If we're SPARC/32-bit, see if we can get extra
334*0Sstevel@tonic-gate 			 * register state for this lwp.  If it's a v8plus
335*0Sstevel@tonic-gate 			 * program, print the 64-bit register values.
336*0Sstevel@tonic-gate 			 */
337*0Sstevel@tonic-gate 			prxregset_t prx;
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate 			if (Plwp_getxregs(Pr, psp->pr_lwpid, &prx) == 0 &&
340*0Sstevel@tonic-gate 			    prx.pr_type == XR_TYPE_V8P)
341*0Sstevel@tonic-gate 				dumpregs_v8p(psp->pr_reg, &prx, is64);
342*0Sstevel@tonic-gate 			else
343*0Sstevel@tonic-gate #endif	/* __sparc && _ILP32 */
344*0Sstevel@tonic-gate 				dumpregs(psp->pr_reg, is64);
345*0Sstevel@tonic-gate 		} else
346*0Sstevel@tonic-gate 			(void) printf("\tNot stopped, can't show registers\n");
347*0Sstevel@tonic-gate 	}
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	return (0);
350*0Sstevel@tonic-gate }
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate static char *
353*0Sstevel@tonic-gate prflags(int arg)
354*0Sstevel@tonic-gate {
355*0Sstevel@tonic-gate 	static char code_buf[200];
356*0Sstevel@tonic-gate 	char *str = code_buf;
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate 	if (arg == 0)
359*0Sstevel@tonic-gate 		return ("0");
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate 	if (arg & ~ALLFLAGS)
362*0Sstevel@tonic-gate 		(void) sprintf(str, "0x%x", arg & ~ALLFLAGS);
363*0Sstevel@tonic-gate 	else
364*0Sstevel@tonic-gate 		*str = '\0';
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 	/*
367*0Sstevel@tonic-gate 	 * Display the semi-permanent lwp flags first.
368*0Sstevel@tonic-gate 	 */
369*0Sstevel@tonic-gate 	if (arg & PR_DAEMON)		/* daemons are always detached so */
370*0Sstevel@tonic-gate 		(void) strcat(str, "|DAEMON");
371*0Sstevel@tonic-gate 	else if (arg & PR_DETACH)	/* report detach only if non-daemon */
372*0Sstevel@tonic-gate 		(void) strcat(str, "|DETACH");
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate 	if (arg & PR_STOPPED)
375*0Sstevel@tonic-gate 		(void) strcat(str, "|STOPPED");
376*0Sstevel@tonic-gate 	if (arg & PR_ISTOP)
377*0Sstevel@tonic-gate 		(void) strcat(str, "|ISTOP");
378*0Sstevel@tonic-gate 	if (arg & PR_DSTOP)
379*0Sstevel@tonic-gate 		(void) strcat(str, "|DSTOP");
380*0Sstevel@tonic-gate #if 0		/* displayed elsewhere */
381*0Sstevel@tonic-gate 	if (arg & PR_ASLEEP)
382*0Sstevel@tonic-gate 		(void) strcat(str, "|ASLEEP");
383*0Sstevel@tonic-gate #endif
384*0Sstevel@tonic-gate 	if (arg & PR_PCINVAL)
385*0Sstevel@tonic-gate 		(void) strcat(str, "|PCINVAL");
386*0Sstevel@tonic-gate 	if (arg & PR_STEP)
387*0Sstevel@tonic-gate 		(void) strcat(str, "|STEP");
388*0Sstevel@tonic-gate 	if (arg & PR_AGENT)
389*0Sstevel@tonic-gate 		(void) strcat(str, "|AGENT");
390*0Sstevel@tonic-gate 	if (arg & PR_ISSYS)
391*0Sstevel@tonic-gate 		(void) strcat(str, "|ISSYS");
392*0Sstevel@tonic-gate 	if (arg & PR_VFORKP)
393*0Sstevel@tonic-gate 		(void) strcat(str, "|VFORKP");
394*0Sstevel@tonic-gate 	if (arg & PR_ORPHAN)
395*0Sstevel@tonic-gate 		(void) strcat(str, "|ORPHAN");
396*0Sstevel@tonic-gate 	if (arg & PR_FORK)
397*0Sstevel@tonic-gate 		(void) strcat(str, "|FORK");
398*0Sstevel@tonic-gate 	if (arg & PR_RLC)
399*0Sstevel@tonic-gate 		(void) strcat(str, "|RLC");
400*0Sstevel@tonic-gate 	if (arg & PR_KLC)
401*0Sstevel@tonic-gate 		(void) strcat(str, "|KLC");
402*0Sstevel@tonic-gate 	if (arg & PR_ASYNC)
403*0Sstevel@tonic-gate 		(void) strcat(str, "|ASYNC");
404*0Sstevel@tonic-gate 	if (arg & PR_BPTADJ)
405*0Sstevel@tonic-gate 		(void) strcat(str, "|BPTADJ");
406*0Sstevel@tonic-gate 	if (arg & PR_MSACCT)
407*0Sstevel@tonic-gate 		(void) strcat(str, "|MSACCT");
408*0Sstevel@tonic-gate 	if (arg & PR_MSFORK)
409*0Sstevel@tonic-gate 		(void) strcat(str, "|MSFORK");
410*0Sstevel@tonic-gate 	if (arg & PR_PTRACE)
411*0Sstevel@tonic-gate 		(void) strcat(str, "|PTRACE");
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate 	if (*str == '|')
414*0Sstevel@tonic-gate 		str++;
415*0Sstevel@tonic-gate 
416*0Sstevel@tonic-gate 	return (str);
417*0Sstevel@tonic-gate }
418*0Sstevel@tonic-gate 
419*0Sstevel@tonic-gate static char *
420*0Sstevel@tonic-gate prwhy(int why)
421*0Sstevel@tonic-gate {
422*0Sstevel@tonic-gate 	static char buf[20];
423*0Sstevel@tonic-gate 	char *str;
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate 	switch (why) {
426*0Sstevel@tonic-gate 	case PR_REQUESTED:
427*0Sstevel@tonic-gate 		str = "PR_REQUESTED";
428*0Sstevel@tonic-gate 		break;
429*0Sstevel@tonic-gate 	case PR_SIGNALLED:
430*0Sstevel@tonic-gate 		str = "PR_SIGNALLED";
431*0Sstevel@tonic-gate 		break;
432*0Sstevel@tonic-gate 	case PR_SYSENTRY:
433*0Sstevel@tonic-gate 		str = "PR_SYSENTRY";
434*0Sstevel@tonic-gate 		break;
435*0Sstevel@tonic-gate 	case PR_SYSEXIT:
436*0Sstevel@tonic-gate 		str = "PR_SYSEXIT";
437*0Sstevel@tonic-gate 		break;
438*0Sstevel@tonic-gate 	case PR_JOBCONTROL:
439*0Sstevel@tonic-gate 		str = "PR_JOBCONTROL";
440*0Sstevel@tonic-gate 		break;
441*0Sstevel@tonic-gate 	case PR_FAULTED:
442*0Sstevel@tonic-gate 		str = "PR_FAULTED";
443*0Sstevel@tonic-gate 		break;
444*0Sstevel@tonic-gate 	case PR_SUSPENDED:
445*0Sstevel@tonic-gate 		str = "PR_SUSPENDED";
446*0Sstevel@tonic-gate 		break;
447*0Sstevel@tonic-gate 	default:
448*0Sstevel@tonic-gate 		str = buf;
449*0Sstevel@tonic-gate 		(void) sprintf(str, "%d", why);
450*0Sstevel@tonic-gate 		break;
451*0Sstevel@tonic-gate 	}
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate 	return (str);
454*0Sstevel@tonic-gate }
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate static char *
457*0Sstevel@tonic-gate prwhat(int why, int what)
458*0Sstevel@tonic-gate {
459*0Sstevel@tonic-gate 	static char buf[32];
460*0Sstevel@tonic-gate 	char *str;
461*0Sstevel@tonic-gate 
462*0Sstevel@tonic-gate 	switch (why) {
463*0Sstevel@tonic-gate 	case PR_SIGNALLED:
464*0Sstevel@tonic-gate 	case PR_JOBCONTROL:
465*0Sstevel@tonic-gate 		str = proc_signame(what, buf, sizeof (buf));
466*0Sstevel@tonic-gate 		break;
467*0Sstevel@tonic-gate 	case PR_SYSENTRY:
468*0Sstevel@tonic-gate 	case PR_SYSEXIT:
469*0Sstevel@tonic-gate 		str = proc_sysname(what, buf, sizeof (buf));
470*0Sstevel@tonic-gate 		break;
471*0Sstevel@tonic-gate 	case PR_FAULTED:
472*0Sstevel@tonic-gate 		str = proc_fltname(what, buf, sizeof (buf));
473*0Sstevel@tonic-gate 		break;
474*0Sstevel@tonic-gate 	default:
475*0Sstevel@tonic-gate 		(void) sprintf(str = buf, "%d", what);
476*0Sstevel@tonic-gate 		break;
477*0Sstevel@tonic-gate 	}
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate 	return (str);
480*0Sstevel@tonic-gate }
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate #if defined(__sparc)
483*0Sstevel@tonic-gate static const char * const regname[NPRGREG] = {
484*0Sstevel@tonic-gate 	" %g0", " %g1", " %g2", " %g3", " %g4", " %g5", " %g6", " %g7",
485*0Sstevel@tonic-gate 	" %o0", " %o1", " %o2", " %o3", " %o4", " %o5", " %sp", " %o7",
486*0Sstevel@tonic-gate 	" %l0", " %l1", " %l2", " %l3", " %l4", " %l5", " %l6", " %l7",
487*0Sstevel@tonic-gate 	" %i0", " %i1", " %i2", " %i3", " %i4", " %i5", " %fp", " %i7",
488*0Sstevel@tonic-gate #ifdef __sparcv9
489*0Sstevel@tonic-gate 	"%ccr", " %pc", "%npc", "  %y", "%asi", "%fprs"
490*0Sstevel@tonic-gate #else
491*0Sstevel@tonic-gate 	"%psr", " %pc", "%npc", "  %y", "%wim", "%tbr"
492*0Sstevel@tonic-gate #endif
493*0Sstevel@tonic-gate };
494*0Sstevel@tonic-gate #endif	/* __sparc */
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate #if defined(__amd64)
497*0Sstevel@tonic-gate static const char * const regname[NPRGREG] = {
498*0Sstevel@tonic-gate 	"%r15", "%r14", "%r13", "%r12", "%r11", "%r10", " %r9", " %r8",
499*0Sstevel@tonic-gate 	"%rdi", "%rsi", "%rbp", "%rbx", "%rdx", "%rcx", "%rax", "%trapno",
500*0Sstevel@tonic-gate 	"%err", "%rip", " %cs", "%rfl", "%rsp", " %ss", " %fs", " %gs",
501*0Sstevel@tonic-gate 	" %es", " %ds", "%fsbase", "%gsbase"
502*0Sstevel@tonic-gate };
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate static const char * const regname32[NPRGREG32] = {
505*0Sstevel@tonic-gate 	" %gs", " %fs", " %es", " %ds", "%edi", "%esi", "%ebp", "%esp",
506*0Sstevel@tonic-gate 	"%ebx", "%edx", "%ecx", "%eax", "%trapno", "%err", "%eip", " %cs",
507*0Sstevel@tonic-gate 	"%efl", "%uesp", " %ss"
508*0Sstevel@tonic-gate };
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate /* XX64 Do we want to expose this through libproc */
511*0Sstevel@tonic-gate void
512*0Sstevel@tonic-gate prgregset_n_to_32(const prgreg_t *src, prgreg32_t *dst)
513*0Sstevel@tonic-gate {
514*0Sstevel@tonic-gate 	bzero(dst, NPRGREG32 * sizeof (prgreg32_t));
515*0Sstevel@tonic-gate 	dst[GS] = src[REG_GS];
516*0Sstevel@tonic-gate 	dst[FS] = src[REG_FS];
517*0Sstevel@tonic-gate 	dst[DS] = src[REG_DS];
518*0Sstevel@tonic-gate 	dst[ES] = src[REG_ES];
519*0Sstevel@tonic-gate 	dst[EDI] = src[REG_RDI];
520*0Sstevel@tonic-gate 	dst[ESI] = src[REG_RSI];
521*0Sstevel@tonic-gate 	dst[EBP] = src[REG_RBP];
522*0Sstevel@tonic-gate 	dst[EBX] = src[REG_RBX];
523*0Sstevel@tonic-gate 	dst[EDX] = src[REG_RDX];
524*0Sstevel@tonic-gate 	dst[ECX] = src[REG_RCX];
525*0Sstevel@tonic-gate 	dst[EAX] = src[REG_RAX];
526*0Sstevel@tonic-gate 	dst[TRAPNO] = src[REG_TRAPNO];
527*0Sstevel@tonic-gate 	dst[ERR] = src[REG_ERR];
528*0Sstevel@tonic-gate 	dst[EIP] = src[REG_RIP];
529*0Sstevel@tonic-gate 	dst[CS] = src[REG_CS];
530*0Sstevel@tonic-gate 	dst[EFL] = src[REG_RFL];
531*0Sstevel@tonic-gate 	dst[UESP] = src[REG_RSP];
532*0Sstevel@tonic-gate 	dst[SS] = src[REG_SS];
533*0Sstevel@tonic-gate }
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate #elif defined(__i386)
536*0Sstevel@tonic-gate static const char * const regname[NPRGREG] = {
537*0Sstevel@tonic-gate 	" %gs", " %fs", " %es", " %ds", "%edi", "%esi", "%ebp", "%esp",
538*0Sstevel@tonic-gate 	"%ebx", "%edx", "%ecx", "%eax", "%trapno", "%err", "%eip", " %cs",
539*0Sstevel@tonic-gate 	"%efl", "%uesp", " %ss"
540*0Sstevel@tonic-gate };
541*0Sstevel@tonic-gate #endif /* __i386 */
542*0Sstevel@tonic-gate 
543*0Sstevel@tonic-gate #if defined(__amd64) && defined(_LP64)
544*0Sstevel@tonic-gate static void
545*0Sstevel@tonic-gate dumpregs32(const prgregset_t reg)
546*0Sstevel@tonic-gate {
547*0Sstevel@tonic-gate 	prgregset32_t reg32;
548*0Sstevel@tonic-gate 	int i;
549*0Sstevel@tonic-gate 
550*0Sstevel@tonic-gate 	prgregset_n_to_32(reg, reg32);
551*0Sstevel@tonic-gate 
552*0Sstevel@tonic-gate 	for (i = 0; i < NPRGREG32; i++) {
553*0Sstevel@tonic-gate 		(void) printf("  %s = 0x%.8X",
554*0Sstevel@tonic-gate 			regname32[i], reg32[i]);
555*0Sstevel@tonic-gate 		if ((i+1) % 4 == 0)
556*0Sstevel@tonic-gate 			(void) putchar('\n');
557*0Sstevel@tonic-gate 	}
558*0Sstevel@tonic-gate 	if (i % 4 != 0)
559*0Sstevel@tonic-gate 		(void) putchar('\n');
560*0Sstevel@tonic-gate }
561*0Sstevel@tonic-gate #endif
562*0Sstevel@tonic-gate 
563*0Sstevel@tonic-gate static void
564*0Sstevel@tonic-gate dumpregs(const prgregset_t reg, int is64)
565*0Sstevel@tonic-gate {
566*0Sstevel@tonic-gate 	int width = is64? 16 : 8;
567*0Sstevel@tonic-gate 	int cols = is64? 2 : 4;
568*0Sstevel@tonic-gate 	int i;
569*0Sstevel@tonic-gate 
570*0Sstevel@tonic-gate #if defined(__amd64) && defined(_LP64)
571*0Sstevel@tonic-gate 	if (!is64) {
572*0Sstevel@tonic-gate 		dumpregs32(reg);
573*0Sstevel@tonic-gate 		return;
574*0Sstevel@tonic-gate 	}
575*0Sstevel@tonic-gate #endif
576*0Sstevel@tonic-gate 
577*0Sstevel@tonic-gate 	for (i = 0; i < NPRGREG; i++) {
578*0Sstevel@tonic-gate 		(void) printf("  %s = 0x%.*lX",
579*0Sstevel@tonic-gate 			regname[i], width, (long)reg[i]);
580*0Sstevel@tonic-gate 		if ((i+1) % cols == 0)
581*0Sstevel@tonic-gate 			(void) putchar('\n');
582*0Sstevel@tonic-gate 	}
583*0Sstevel@tonic-gate 	if (i % cols != 0)
584*0Sstevel@tonic-gate 		(void) putchar('\n');
585*0Sstevel@tonic-gate }
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate #if defined(__sparc) && defined(_ILP32)
588*0Sstevel@tonic-gate static void
589*0Sstevel@tonic-gate dumpregs_v8p(const prgregset_t reg, const prxregset_t *xreg, int is64)
590*0Sstevel@tonic-gate {
591*0Sstevel@tonic-gate 	static const uint32_t zero[8] = { 0 };
592*0Sstevel@tonic-gate 	int gr, xr, cols = 2;
593*0Sstevel@tonic-gate 	uint64_t xval;
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate 	if (memcmp(xreg->pr_un.pr_v8p.pr_xg, zero, sizeof (zero)) == 0 &&
596*0Sstevel@tonic-gate 	    memcmp(xreg->pr_un.pr_v8p.pr_xo, zero, sizeof (zero)) == 0) {
597*0Sstevel@tonic-gate 		dumpregs(reg, is64);
598*0Sstevel@tonic-gate 		return;
599*0Sstevel@tonic-gate 	}
600*0Sstevel@tonic-gate 
601*0Sstevel@tonic-gate 	for (gr = R_G0, xr = XR_G0; gr <= R_G7; gr++, xr++) {
602*0Sstevel@tonic-gate 		xval = (uint64_t)xreg->pr_un.pr_v8p.pr_xg[xr] << 32 |
603*0Sstevel@tonic-gate 		    (uint64_t)(uint32_t)reg[gr];
604*0Sstevel@tonic-gate 		(void) printf("  %s = 0x%.16" PRIX64, regname[gr], xval);
605*0Sstevel@tonic-gate 		if ((gr + 1) % cols == 0)
606*0Sstevel@tonic-gate 			(void) putchar('\n');
607*0Sstevel@tonic-gate 	}
608*0Sstevel@tonic-gate 
609*0Sstevel@tonic-gate 	for (gr = R_O0, xr = XR_O0; gr <= R_O7; gr++, xr++) {
610*0Sstevel@tonic-gate 		xval = (uint64_t)xreg->pr_un.pr_v8p.pr_xo[xr] << 32 |
611*0Sstevel@tonic-gate 		    (uint64_t)(uint32_t)reg[gr];
612*0Sstevel@tonic-gate 		(void) printf("  %s = 0x%.16" PRIX64, regname[gr], xval);
613*0Sstevel@tonic-gate 		if ((gr + 1) % cols == 0)
614*0Sstevel@tonic-gate 			(void) putchar('\n');
615*0Sstevel@tonic-gate 	}
616*0Sstevel@tonic-gate 
617*0Sstevel@tonic-gate 	for (gr = R_L0; gr < NPRGREG; gr++) {
618*0Sstevel@tonic-gate 		(void) printf("  %s =         0x%.8lX",
619*0Sstevel@tonic-gate 		    regname[gr], (long)reg[gr]);
620*0Sstevel@tonic-gate 		if ((gr + 1) % cols == 0)
621*0Sstevel@tonic-gate 			(void) putchar('\n');
622*0Sstevel@tonic-gate 	}
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate 	if (gr % cols != 0)
625*0Sstevel@tonic-gate 		(void) putchar('\n');
626*0Sstevel@tonic-gate }
627*0Sstevel@tonic-gate #endif	/* __sparc && _ILP32 */
628