xref: /illumos-gate/usr/src/cmd/ptools/pflags/pflags.c (revision 4e93fb0f6383eaac21897dcdae56b87118131e4d)
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