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