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