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