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