Print this page
    
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/mdb/common/modules/libc/libc.c
          +++ new/usr/src/cmd/mdb/common/modules/libc/libc.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   * Copyright (c) 2012 by Delphix. All rights reserved.
  25   25   * Copyright 2016, Joyent, Inc.
  26   26   */
  27   27  
  28   28  #include <sys/mdb_modapi.h>
  29   29  #include <mdb/mdb_whatis.h>
  30   30  #include <mdb/mdb_ctf.h>
  31   31  #include <procfs.h>
  32   32  #include <ucontext.h>
  33   33  #include <siginfo.h>
  34   34  #include <signal.h>
  35   35  #include <setjmp.h>
  36   36  #include <string.h>
  37   37  #include <thr_uberdata.h>
  38   38  #include "findstack.h"
  39   39  
  40   40  static const char *
  41   41  stack_flags(const stack_t *sp)
  42   42  {
  43   43          static char buf[32];
  44   44  
  45   45          if (sp->ss_flags == 0)
  46   46                  (void) strcpy(buf, " 0");
  47   47          else if (sp->ss_flags & ~(SS_ONSTACK | SS_DISABLE))
  48   48                  (void) mdb_snprintf(buf, sizeof (buf), " 0x%x", sp->ss_flags);
  49   49          else {
  50   50                  buf[0] = '\0';
  51   51                  if (sp->ss_flags & SS_ONSTACK)
  52   52                          (void) strcat(buf, "|ONSTACK");
  53   53                  if (sp->ss_flags & SS_DISABLE)
  54   54                          (void) strcat(buf, "|DISABLE");
  55   55          }
  56   56  
  57   57          return (buf + 1);
  58   58  }
  59   59  
  60   60  /*ARGSUSED*/
  61   61  static int
  62   62  d_jmp_buf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
  63   63  {
  64   64          jmp_buf jb;
  65   65          const ulong_t *b = (const ulong_t *)jb;
  66   66  
  67   67          if (argc != 0)
  68   68                  return (DCMD_USAGE);
  69   69  
  70   70          if (mdb_vread(&jb, sizeof (jb), addr) != sizeof (jb)) {
  71   71                  mdb_warn("failed to read jmp_buf at %p", addr);
  72   72                  return (DCMD_ERR);
  73   73          }
  74   74  
  75   75  #if defined(__sparc)
  76   76          mdb_printf("  %%sp = 0x%lx\n", b[1]);
  77   77          mdb_printf("  %%pc = 0x%lx %lA\n", b[2], b[2]);
  78   78          mdb_printf("  %%fp = 0x%lx\n", b[3]);
  79   79          mdb_printf("  %%i7 = 0x%lx %lA\n", b[4], b[4]);
  80   80  #elif defined(__amd64)
  81   81          mdb_printf("  %%rbx = 0x%lx\n", b[0]);
  82   82          mdb_printf("  %%r12 = 0x%lx\n", b[1]);
  83   83          mdb_printf("  %%r13 = 0x%lx\n", b[2]);
  84   84          mdb_printf("  %%r14 = 0x%lx\n", b[3]);
  85   85          mdb_printf("  %%r15 = 0x%lx\n", b[4]);
  86   86          mdb_printf("  %%rbp = 0x%lx\n", b[5]);
  87   87          mdb_printf("  %%rsp = 0x%lx\n", b[6]);
  88   88          mdb_printf("  %%rip = 0x%lx %lA\n", b[7], b[7]);
  89   89  #elif defined(__i386)
  90   90          mdb_printf("  %%ebx = 0x%lx\n", b[0]);
  91   91          mdb_printf("  %%esi = 0x%lx\n", b[1]);
  92   92          mdb_printf("  %%edi = 0x%lx\n", b[2]);
  93   93          mdb_printf("  %%ebp = 0x%lx\n", b[3]);
  94   94          mdb_printf("  %%esp = 0x%lx\n", b[4]);
  95   95          mdb_printf("  %%eip = 0x%lx %lA\n", b[5], b[5]);
  96   96  #endif
  97   97          return (DCMD_OK);
  98   98  }
  99   99  
 100  100  const mdb_bitmask_t uc_flags_bits[] = {
 101  101          { "UC_SIGMASK", UC_SIGMASK, UC_SIGMASK },
 102  102          { "UC_STACK", UC_STACK, UC_STACK },
 103  103          { "UC_CPU", UC_CPU, UC_CPU },
 104  104          { "UC_FPU", UC_FPU, UC_FPU },
 105  105  #if defined(UC_INTR)
 106  106          { "UC_INTR", UC_INTR, UC_INTR },
 107  107  #endif
 108  108  #if defined(UC_ASR)
 109  109          { "UC_ASR", UC_ASR, UC_ASR },
 110  110  #endif
 111  111          { NULL, 0, 0 }
 112  112  };
 113  113  
 114  114  /*ARGSUSED*/
 115  115  static int
 116  116  d_ucontext(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 117  117  {
 118  118          ucontext_t uc;
 119  119  
 120  120          if (argc != 0)
 121  121                  return (DCMD_USAGE);
 122  122  
 123  123          if (mdb_vread(&uc, sizeof (uc), addr) != sizeof (uc)) {
 124  124                  mdb_warn("failed to read ucontext at %p", addr);
 125  125                  return (DCMD_ERR);
 126  126          }
 127  127  
 128  128          mdb_printf("  flags    = 0x%lx <%b>\n", uc.uc_flags,
 129  129              (uint_t)uc.uc_flags, uc_flags_bits);
 130  130          mdb_printf("  link     = 0x%p\n", uc.uc_link);
 131  131          mdb_printf("  sigmask  = 0x%08x 0x%08x 0x%08x 0x%08x\n",
 132  132              uc.uc_sigmask.__sigbits[0], uc.uc_sigmask.__sigbits[1],
 133  133              uc.uc_sigmask.__sigbits[2], uc.uc_sigmask.__sigbits[3]);
 134  134          mdb_printf("  stack    = sp 0x%p size 0x%lx flags %s\n",
 135  135              uc.uc_stack.ss_sp, uc.uc_stack.ss_size, stack_flags(&uc.uc_stack));
 136  136          mdb_printf("  mcontext = 0x%p\n",
 137  137              addr + OFFSETOF(ucontext_t, uc_mcontext));
 138  138          mdb_printf("  brand    = 0x%p 0x%p 0x%p\n",
 139  139              uc.uc_brand_data[0], uc.uc_brand_data[1], uc.uc_brand_data[2]);
 140  140  
 141  141          return (DCMD_OK);
 142  142  }
 143  143  
 144  144  /*ARGSUSED*/
 145  145  static int
 146  146  d_sigjmp_buf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 147  147  {
 148  148  #if defined(__sparc)
 149  149          struct {
 150  150                  int sjs_flags;
 151  151                  greg_t sjs_sp;
 152  152                  greg_t sjs_pc;
 153  153                  greg_t sjs_fp;
 154  154                  greg_t sjs_i7;
 155  155                  ucontext_t *sjs_uclink;
 156  156                  ulong_t sjs_pad[_JBLEN - 6];
 157  157                  sigset_t sjs_sigmask;
 158  158  #if defined(_LP64)
 159  159                  greg_t sjs_asi;
 160  160                  greg_t sjs_fprs;
 161  161  #endif
 162  162                  stack_t sjs_stack;
 163  163          } s;
 164  164  
 165  165          if (argc != 0)
 166  166                  return (DCMD_USAGE);
 167  167  
 168  168          if (mdb_vread(&s, sizeof (s), addr) != sizeof (s)) {
 169  169                  mdb_warn("failed to read sigjmp_buf at %p", addr);
 170  170                  return (DCMD_ERR);
 171  171          }
 172  172  
 173  173          mdb_printf("  flags  = 0x%x\n", s.sjs_flags);
 174  174          mdb_printf("  %%sp    = 0x%lx %lA\n", s.sjs_sp, s.sjs_sp);
 175  175          mdb_printf("  %%pc    = 0x%lx %lA\n", s.sjs_pc, s.sjs_pc);
 176  176          mdb_printf("  %%fp    = 0x%lx %lA\n", s.sjs_fp, s.sjs_fp);
 177  177          mdb_printf("  %%i7    = 0x%lx %lA\n", s.sjs_i7, s.sjs_i7);
 178  178          mdb_printf("  uclink = %p\n", s.sjs_uclink);
 179  179          mdb_printf("  sigset = 0x%08x 0x%08x 0x%08x 0x%08x\n",
 180  180              s.sjs_sigmask.__sigbits[0], s.sjs_sigmask.__sigbits[1],
 181  181              s.sjs_sigmask.__sigbits[2], s.sjs_sigmask.__sigbits[3]);
 182  182  #if defined(_LP64)
 183  183          mdb_printf("  %%asi   = 0x%lx\n", s.sjs_asi);
 184  184          mdb_printf("  %%fprs  = 0x%lx\n", s.sjs_fprs);
 185  185  #endif
 186  186          mdb_printf("  stack  = sp 0x%p size 0x%lx flags %s\n",
 187  187              s.sjs_stack.ss_sp, s.sjs_stack.ss_size, stack_flags(&s.sjs_stack));
 188  188  
 189  189          return (DCMD_OK);
 190  190  
 191  191  #elif defined(__i386) || defined(__amd64)
 192  192          return (d_ucontext(addr, flags, argc, argv));
 193  193  #endif
 194  194  }
 195  195  
 196  196  /*ARGSUSED*/
 197  197  static int
 198  198  d_siginfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 199  199  {
 200  200          static const char *const msname[] = {
 201  201                  "USER", "SYSTEM", "TRAP", "TFAULT", "DFAULT", "KFAULT",
 202  202                  "USER_LOCK", "SLEEP", "WAIT_CPU", "STOPPED"
 203  203          };
 204  204  
 205  205          char signame[SIG2STR_MAX];
 206  206          siginfo_t si;
 207  207          int i;
 208  208  
 209  209          if (argc != 0)
 210  210                  return (DCMD_USAGE);
 211  211  
 212  212          if (mdb_vread(&si, sizeof (si), addr) != sizeof (si)) {
 213  213                  mdb_warn("failed to read siginfo at %p", addr);
 214  214                  return (DCMD_ERR);
 215  215          }
 216  216  
 217  217          if (sig2str(si.si_signo, signame) == -1)
 218  218                  (void) strcpy(signame, "unknown");
 219  219  
 220  220          mdb_printf("  signal %5d (%s)\n", si.si_signo, signame);
 221  221          mdb_printf("  code   %5d (", si.si_code);
 222  222  
 223  223          switch (si.si_code) {
 224  224          case SI_NOINFO:
 225  225                  mdb_printf("no info");
 226  226                  break;
 227  227          case SI_DTRACE:
 228  228                  mdb_printf("from DTrace raise() action");
 229  229                  break;
 230  230          case SI_RCTL:
 231  231                  mdb_printf("from rctl action");
 232  232                  break;
 233  233          case SI_USER:
 234  234                  mdb_printf("user generated via kill");
 235  235                  break;
 236  236          case SI_LWP:
 237  237                  mdb_printf("user generated via lwp_kill");
 238  238                  break;
 239  239          case SI_QUEUE:
 240  240                  mdb_printf("user generated via sigqueue");
 241  241                  break;
 242  242          case SI_TIMER:
 243  243                  mdb_printf("from timer expiration");
 244  244                  break;
 245  245          case SI_ASYNCIO:
 246  246                  mdb_printf("from async i/o completion");
 247  247                  break;
 248  248          case SI_MESGQ:
 249  249                  mdb_printf("from message arrival");
 250  250                  break;
 251  251          default:
 252  252                  if (SI_FROMUSER(&si))
 253  253                          mdb_printf("from user process");
 254  254                  else
 255  255                          mdb_printf("from kernel");
 256  256          }
 257  257  
 258  258          mdb_printf(")\n  errno  %5d (%s)\n",
 259  259              si.si_errno, strerror(si.si_errno));
 260  260  
 261  261          if (si.si_code == SI_USER || si.si_code == SI_QUEUE) {
 262  262                  mdb_printf("  signal sent from PID %d (uid %d)\n",
 263  263                      si.si_pid, si.si_uid);
 264  264          }
 265  265  
 266  266          if (si.si_code == SI_QUEUE) {
 267  267                  mdb_printf("  signal value = 0t%d / %p\n",
 268  268                      si.si_value.sival_int, si.si_value.sival_ptr);
 269  269          }
 270  270  
 271  271          switch (si.si_signo) {
 272  272          case SIGCLD:
 273  273                  mdb_printf("  signal sent from child PID %d (uid %d)\n",
 274  274                      si.si_pid, si.si_uid);
 275  275                  mdb_printf("  usr time = 0t%ld ticks, sys time = 0t%ld ticks\n",
 276  276                      si.si_utime, si.si_stime);
 277  277                  mdb_printf("  wait status = 0x%x\n", si.si_status);
 278  278                  break;
 279  279  
 280  280          case SIGSEGV:
 281  281          case SIGBUS:
 282  282          case SIGILL:
 283  283          case SIGTRAP:
 284  284          case SIGFPE:
 285  285                  mdb_printf("  fault address = 0x%p\n  trapno = %d\n",
 286  286                      si.si_addr, si.si_trapno);
 287  287                  mdb_printf("  instruction address = 0x%p %lA\n",
 288  288                      si.si_pc, si.si_pc);
 289  289                  break;
 290  290  
 291  291          case SIGPOLL:
 292  292          case SIGXFSZ:
 293  293                  mdb_printf("  fd = %d  band = 0x%lx\n",
 294  294                      si.si_fd, si.si_band);
 295  295                  break;
 296  296  
 297  297          case SIGPROF:
 298  298                  mdb_printf("  last fault address = 0x%p fault type = %d\n",
 299  299                      si.si_faddr, si.si_fault);
 300  300                  mdb_printf("  timestamp = 0t%ld sec 0t%ld nsec\n",
 301  301                      si.si_tstamp.tv_sec, si.si_tstamp.tv_nsec);
 302  302  
 303  303                  if (si.__data.__prof.__syscall != 0) {
 304  304                          mdb_printf("  system call %d (", si.si_syscall);
 305  305                          if (si.si_nsysarg > 0) {
 306  306                                  mdb_printf("%lx", si.si_sysarg[0]);
 307  307                                  for (i = 1; i < si.si_nsysarg; i++)
 308  308                                          mdb_printf(", %lx", si.si_sysarg[i]);
 309  309                          }
 310  310                          mdb_printf("  )\n");
 311  311                  }
 312  312  
 313  313                  for (i = 0; i < sizeof (msname) / sizeof (msname[0]); i++) {
 314  314                          mdb_printf("  mstate[\"%s\"] = %d\n",
 315  315                              msname[i], si.si_mstate[i]);
 316  316                  }
 317  317                  break;
 318  318          }
 319  319  
 320  320          return (DCMD_OK);
 321  321  }
 322  322  
 323  323  static int
 324  324  uc_walk_step(mdb_walk_state_t *wsp)
 325  325  {
 326  326          uintptr_t addr = wsp->walk_addr;
 327  327          ucontext_t uc;
 328  328  
 329  329          if (addr == NULL)
 330  330                  return (WALK_DONE);
 331  331  
 332  332          if (mdb_vread(&uc, sizeof (uc), addr) != sizeof (uc)) {
 333  333                  mdb_warn("failed to read ucontext at %p", addr);
 334  334                  return (WALK_ERR);
 335  335          }
 336  336  
 337  337          wsp->walk_addr = (uintptr_t)uc.uc_link;
 338  338          return (wsp->walk_callback(addr, &uc, wsp->walk_cbdata));
 339  339  }
 340  340  
 341  341  static int
 342  342  oldc_walk_init(mdb_walk_state_t *wsp)
 343  343  {
 344  344          ssize_t nbytes = mdb_get_xdata("lwpstatus", NULL, 0);
 345  345  
 346  346          if (nbytes <= 0) {
 347  347                  mdb_warn("lwpstatus information not available");
 348  348                  return (WALK_ERR);
 349  349          }
 350  350  
 351  351          if (wsp->walk_addr != NULL) {
 352  352                  mdb_warn("walker only supports global walk\n");
 353  353                  return (WALK_ERR);
 354  354          }
 355  355  
 356  356          wsp->walk_addr = nbytes; /* Use walk_addr to track size */
 357  357          wsp->walk_data = mdb_alloc(nbytes, UM_SLEEP);
 358  358  
 359  359          if (mdb_get_xdata("lwpstatus", wsp->walk_data, nbytes) != nbytes) {
 360  360                  mdb_warn("failed to read lwpstatus information");
 361  361                  mdb_free(wsp->walk_data, nbytes);
 362  362                  return (WALK_ERR);
 363  363          }
 364  364  
 365  365          wsp->walk_arg = wsp->walk_data; /* Use walk_arg to track pointer */
 366  366          return (WALK_NEXT);
 367  367  }
 368  368  
 369  369  static int
 370  370  oldc_walk_step(mdb_walk_state_t *wsp)
 371  371  {
 372  372          const lwpstatus_t *lsp, *end;
 373  373  
 374  374          end = (const lwpstatus_t *)((uintptr_t)wsp->walk_data + wsp->walk_addr);
 375  375          lsp = wsp->walk_arg;
 376  376  
 377  377          wsp->walk_arg = (void *)(lsp + 1);
 378  378  
 379  379          if (lsp < end) {
 380  380                  uintptr_t addr = lsp->pr_oldcontext;
 381  381                  ucontext_t uc;
 382  382  
 383  383                  if (addr == NULL)
 384  384                          return (WALK_NEXT);
 385  385  
 386  386                  if (mdb_vread(&uc, sizeof (uc), addr) != sizeof (uc)) {
 387  387                          mdb_warn("failed to read ucontext at %p", addr);
 388  388                          return (WALK_NEXT);
 389  389                  }
 390  390  
 391  391                  return (wsp->walk_callback(addr, &uc, wsp->walk_cbdata));
 392  392          }
 393  393  
 394  394          return (WALK_DONE);
 395  395  }
 396  396  
 397  397  static void
 398  398  oldc_walk_fini(mdb_walk_state_t *wsp)
 399  399  {
 400  400          mdb_free(wsp->walk_data, wsp->walk_addr); /* walk_addr has size */
 401  401  }
 402  402  
 403  403  /*
 404  404   * ==================== threads ==========================
 405  405   * These are the interfaces that used to require libthread.
 406  406   * Now, libthread has been folded into libc.
 407  407   * =======================================================
 408  408   */
 409  409  
 410  410  /*
 411  411   * prt_addr() is called up to three times to generate arguments for
 412  412   * one call to mdb_printf().  We must return at least three different
 413  413   * pointers to static storage for consecutive calls to prt_addr().
 414  414   */
 415  415  static const char *
 416  416  prt_addr(void *addr, int pad)
 417  417  {
 418  418          static char buffer[4][24];
 419  419          static int ix = 0;
 420  420          char *buf;
 421  421  
 422  422          if (ix == 4)    /* use buffers in sequence: 0, 1, 2, 3 */
 423  423                  ix = 0;
 424  424          buf = buffer[ix++];
 425  425          if (addr == NULL)
 426  426                  return (pad? "<NULL>               " : "<NULL>");
 427  427          else {
 428  428  #ifdef _LP64
 429  429                  (void) mdb_snprintf(buf, sizeof (buffer[0]), "0x%016lx", addr);
 430  430                  if (pad)
 431  431                          (void) strcpy(buf + 18, "   ");
 432  432  #else
 433  433                  (void) mdb_snprintf(buf, sizeof (buffer[0]), "0x%08lx", addr);
 434  434                  if (pad)
 435  435                          (void) strcpy(buf + 10, "           ");
 436  436  #endif  /* _LP64 */
 437  437                  return (buf);
 438  438          }
 439  439  }
 440  440  
 441  441  #define HD(str)         mdb_printf("           " str "\n")
 442  442  #define OFFSTR          "+0x%-7lx "
 443  443  #define OFFSET(member)  ((size_t)OFFSETOF(ulwp_t, member))
 444  444  
 445  445  /*ARGSUSED*/
 446  446  static int
 447  447  d_ulwp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 448  448  {
 449  449          ulwp_t ulwp;
 450  450  
 451  451          if (argc != 0 || !(flags & DCMD_ADDRSPEC))
 452  452                  return (DCMD_USAGE);
 453  453  
 454  454          if (mdb_vread(&ulwp, sizeof (ulwp), addr) != sizeof (ulwp) &&
 455  455              (bzero(&ulwp, sizeof (ulwp)),
 456  456              mdb_vread(&ulwp, REPLACEMENT_SIZE, addr)) != REPLACEMENT_SIZE) {
 457  457                  mdb_warn("failed to read ulwp at 0x%p", addr);
 458  458                  return (DCMD_ERR);
 459  459          }
 460  460  
 461  461          mdb_printf("%#a\n", addr);
 462  462  
 463  463          HD("self                  uberdata");
 464  464          mdb_printf(OFFSTR "%s %s\n",
 465  465              OFFSET(ul_self),
 466  466              prt_addr(ulwp.ul_self, 1),
 467  467              prt_addr(ulwp.ul_uberdata, 0));
 468  468  
 469  469          HD("tlsent                ntlsent");
 470  470          mdb_printf(OFFSTR "%s %ld\n",
 471  471              OFFSET(ul_tlsent),
 472  472              prt_addr(ulwp.ul_tlsent, 1),
 473  473              ulwp.ul_ntlsent);
 474  474  
 475  475          HD("forw                  back                  next");
 476  476          mdb_printf(OFFSTR "%s %s %s\n",
 477  477              OFFSET(ul_forw),
 478  478              prt_addr(ulwp.ul_forw, 1),
 479  479              prt_addr(ulwp.ul_back, 1),
 480  480              prt_addr(ulwp.ul_next, 0));
 481  481  
 482  482          HD("hash                  rval                  stk");
 483  483          mdb_printf(OFFSTR "%s %s %s\n",
 484  484              OFFSET(ul_hash),
 485  485              prt_addr(ulwp.ul_hash, 1),
 486  486              prt_addr(ulwp.ul_rval, 1),
 487  487              prt_addr(ulwp.ul_stk, 0));
 488  488  
 489  489          HD("mapsiz     guardsize  stktop                stksiz");
 490  490          mdb_printf(OFFSTR "%-10ld %-10ld %s %ld\n",
 491  491              OFFSET(ul_mapsiz),
 492  492              ulwp.ul_mapsiz,
 493  493              ulwp.ul_guardsize,
 494  494              prt_addr((void *)ulwp.ul_stktop, 1),
 495  495              ulwp.ul_stksiz);
 496  496  
 497  497          HD("ustack.ss_sp          ustack.ss_size        ustack.ss_flags");
 498  498          mdb_printf(OFFSTR "%s %-21ld %s\n",
 499  499              OFFSET(ul_ustack.ss_sp),
 500  500              prt_addr(ulwp.ul_ustack.ss_sp, 1),
 501  501              ulwp.ul_ustack.ss_size,
 502  502              stack_flags(&ulwp.ul_ustack));
 503  503  
 504  504          HD("ix         lwpid      pri        epri       policy     cid");
 505  505          mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n",
 506  506              OFFSET(ul_ix),
 507  507              ulwp.ul_ix,
 508  508              ulwp.ul_lwpid,
 509  509              ulwp.ul_pri,
 510  510              ulwp.ul_epri,
 511  511              ulwp.ul_policy,
 512  512              ulwp.ul_cid);
 513  513  
 514  514          HD("cursig     pleasestop stop       signalled  dead       unwind");
 515  515          mdb_printf(OFFSTR "%-10d ",
 516  516              OFFSET(ul_cursig),
 517  517              ulwp.ul_cursig);
 518  518          mdb_printf(ulwp.ul_pleasestop? "0x%-8x " : "%-10d ",
 519  519              ulwp.ul_pleasestop);
 520  520          mdb_printf(ulwp.ul_stop? "0x%-8x " : "%-10d ",
 521  521              ulwp.ul_stop);
 522  522          mdb_printf("%-10d %-10d %d\n",
 523  523              ulwp.ul_signalled,
 524  524              ulwp.ul_dead,
 525  525              ulwp.ul_unwind);
 526  526  
 527  527          HD("detached   writer     stopping   can'prolog preempt    savpreempt");
 528  528          mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n",
 529  529              OFFSET(ul_detached),
 530  530              ulwp.ul_detached,
 531  531              ulwp.ul_writer,
 532  532              ulwp.ul_stopping,
 533  533              ulwp.ul_cancel_prologue,
 534  534              ulwp.ul_preempt,
 535  535              ulwp.ul_savpreempt);
 536  536  
 537  537          HD("sigsuspend main       fork       primarymap m'spinners d'noreserv");
 538  538          mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n",
 539  539              OFFSET(ul_sigsuspend),
 540  540              ulwp.ul_sigsuspend,
 541  541              ulwp.ul_main,
 542  542              ulwp.ul_fork,
 543  543              ulwp.ul_primarymap,
 544  544              ulwp.ul_max_spinners,
 545  545              ulwp.ul_door_noreserve);
 546  546  
 547  547          HD("queue_fifo c'w'defer  e'detect'  async_safe rt         rtqueued");
 548  548          mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n",
 549  549              OFFSET(ul_queue_fifo),
 550  550              ulwp.ul_queue_fifo,
 551  551              ulwp.ul_cond_wait_defer,
 552  552              ulwp.ul_error_detection,
 553  553              ulwp.ul_async_safe,
 554  554              ulwp.ul_rt,
 555  555              ulwp.ul_rtqueued);
 556  556  
 557  557          HD("misaligned adapt'spin queue_spin critical   sigdefer   vfork");
 558  558          mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n",
 559  559              OFFSET(ul_misaligned),
 560  560              ulwp.ul_misaligned,
 561  561              ulwp.ul_adaptive_spin,
 562  562              ulwp.ul_queue_spin,
 563  563              ulwp.ul_critical,
 564  564              ulwp.ul_sigdefer,
 565  565              ulwp.ul_vfork);
 566  566  
 567  567          HD("cancelable c'pending  c'disabled c'async    save_async mutator");
 568  568          mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n",
 569  569              OFFSET(ul_cancelable),
 570  570              ulwp.ul_cancelable,
 571  571              ulwp.ul_cancel_pending,
 572  572              ulwp.ul_cancel_disabled,
 573  573              ulwp.ul_cancel_async,
 574  574              ulwp.ul_save_async,
 575  575              ulwp.ul_mutator);
 576  576  
 577  577          HD("created    replace    nocancel   errno      errnop");
 578  578          mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %s\n",
 579  579              OFFSET(ul_created),
 580  580              ulwp.ul_created,
 581  581              ulwp.ul_replace,
 582  582              ulwp.ul_nocancel,
 583  583              ulwp.ul_errno,
 584  584              prt_addr(ulwp.ul_errnop, 0));
 585  585  
 586  586          HD("clnup_hdr             schedctl_called       schedctl");
 587  587          mdb_printf(OFFSTR "%s %s %s\n",
 588  588              OFFSET(ul_clnup_hdr),
 589  589              prt_addr(ulwp.ul_clnup_hdr, 1),
 590  590              prt_addr(ulwp.ul_schedctl_called, 1),
 591  591              prt_addr((void *)ulwp.ul_schedctl, 0));
 592  592  
 593  593          HD("bindflags  libc_locks stsd                  &ftsd");
 594  594          mdb_printf(OFFSTR,
 595  595              OFFSET(ul_bindflags));
 596  596          mdb_printf(ulwp.ul_bindflags? "0x%-8x " : "%-10d ",
 597  597              ulwp.ul_bindflags);
 598  598          mdb_printf("%-10d ", ulwp.ul_libc_locks);
 599  599          mdb_printf("%s %s\n",
 600  600              prt_addr(ulwp.ul_stsd, 1),
 601  601              prt_addr((void *)(addr + OFFSET(ul_ftsd[0])), 0));
 602  602  
 603  603          HD("eventmask[0..1]       eventnum              eventdata");
 604  604          mdb_printf(OFFSTR "0x%08x 0x%08x %-21d %s\n",
 605  605              OFFSET(ul_td_evbuf.eventmask.event_bits[0]),
 606  606              ulwp.ul_td_evbuf.eventmask.event_bits[0],
 607  607              ulwp.ul_td_evbuf.eventmask.event_bits[1],
 608  608              ulwp.ul_td_evbuf.eventnum,
 609  609              prt_addr(ulwp.ul_td_evbuf.eventdata, 0));
 610  610  
 611  611          HD("td'enable  sync'reg   qtype      cv_wake    rtld       usropts");
 612  612          mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d ",
 613  613              OFFSET(ul_td_events_enable),
 614  614              ulwp.ul_td_events_enable,
 615  615              ulwp.ul_sync_obj_reg,
 616  616              ulwp.ul_qtype,
 617  617              ulwp.ul_cv_wake,
 618  618              ulwp.ul_rtld);
 619  619          mdb_printf(ulwp.ul_usropts? "0x%x\n" : "%d\n",
 620  620              ulwp.ul_usropts);
 621  621  
 622  622          HD("startpc               startarg              wchan");
 623  623          mdb_printf(OFFSTR "%s %s %s\n",
 624  624              OFFSET(ul_startpc),
 625  625              prt_addr((void *)ulwp.ul_startpc, 1),
 626  626              prt_addr(ulwp.ul_startarg, 1),
 627  627              prt_addr(ulwp.ul_wchan, 0));
 628  628  
 629  629          HD("link                  sleepq                cvmutex");
 630  630          mdb_printf(OFFSTR "%s %s %s\n",
 631  631              OFFSET(ul_link),
 632  632              prt_addr(ulwp.ul_link, 1),
 633  633              prt_addr(ulwp.ul_sleepq, 1),
 634  634              prt_addr(ulwp.ul_cvmutex, 0));
 635  635  
 636  636          HD("mxchain               save_state");
 637  637          mdb_printf(OFFSTR "%s %d\n",
 638  638              OFFSET(ul_mxchain),
 639  639              prt_addr(ulwp.ul_mxchain, 1),
 640  640              ulwp.ul_save_state);
 641  641  
 642  642          HD("rdlockcnt             rd_rwlock             rd_count");
 643  643          mdb_printf(OFFSTR "%-21d %s %d\n",
 644  644              OFFSET(ul_rdlockcnt),
 645  645              ulwp.ul_rdlockcnt,
 646  646              prt_addr(ulwp.ul_readlock.single.rd_rwlock, 1),
 647  647              ulwp.ul_readlock.single.rd_count);
 648  648  
 649  649          HD("heldlockcnt           heldlocks             tpdp");
 650  650          mdb_printf(OFFSTR "%-21d %s %s\n",
 651  651              OFFSET(ul_heldlockcnt),
 652  652              ulwp.ul_heldlockcnt,
 653  653              prt_addr(ulwp.ul_heldlocks.single, 1),
 654  654              prt_addr(ulwp.ul_tpdp, 0));
 655  655  
 656  656          HD("siglink               s'l'spin   s'l'spin2  s'l'sleep  s'l'wakeup");
 657  657          mdb_printf(OFFSTR "%s %-10d %-10d %-10d %d\n",
 658  658              OFFSET(ul_siglink),
 659  659              prt_addr(ulwp.ul_siglink, 1),
 660  660              ulwp.ul_spin_lock_spin,
 661  661              ulwp.ul_spin_lock_spin2,
 662  662              ulwp.ul_spin_lock_sleep,
 663  663              ulwp.ul_spin_lock_wakeup);
 664  664  
 665  665          HD("&queue_root           rtclassid  pilocks");
 666  666          mdb_printf(OFFSTR "%s %-10d %d\n",
 667  667              OFFSET(ul_queue_root),
 668  668              prt_addr((void *)(addr + OFFSET(ul_queue_root)), 1),
 669  669              ulwp.ul_rtclassid,
 670  670              ulwp.ul_pilocks);
 671  671  
 672  672          /*
 673  673           * The remainder of the ulwp_t structure
 674  674           * is invalid if this is a replacement.
 675  675           */
 676  676          if (ulwp.ul_replace)
 677  677                  return (DCMD_OK);
 678  678  
 679  679          HD("sigmask[0..3]");
 680  680          mdb_printf(OFFSTR "0x%08x 0x%08x 0x%08x 0x%08x\n",
 681  681              OFFSET(ul_sigmask.__sigbits[0]),
 682  682              ulwp.ul_sigmask.__sigbits[0],
 683  683              ulwp.ul_sigmask.__sigbits[1],
 684  684              ulwp.ul_sigmask.__sigbits[2],
 685  685              ulwp.ul_sigmask.__sigbits[3]);
 686  686  
 687  687          HD("tmpmask[0..3]");
 688  688          mdb_printf(OFFSTR "0x%08x 0x%08x 0x%08x 0x%08x\n",
 689  689              OFFSET(ul_tmpmask.__sigbits[0]),
 690  690              ulwp.ul_tmpmask.__sigbits[0],
 691  691              ulwp.ul_tmpmask.__sigbits[1],
 692  692              ulwp.ul_tmpmask.__sigbits[2],
 693  693              ulwp.ul_tmpmask.__sigbits[3]);
 694  694  
 695  695          HD("&siginfo              &spinlock             &fpuenv");
 696  696          mdb_printf(OFFSTR "%s %s %s\n",
 697  697              OFFSET(ul_siginfo),
 698  698              prt_addr((void *)(addr + OFFSET(ul_siginfo)), 1),
 699  699              prt_addr((void *)(addr + OFFSET(ul_spinlock)), 1),
 700  700              prt_addr((void *)(addr + OFFSET(ul_fpuenv)), 0));
 701  701  
 702  702          HD("tmem.size             &tmem.roots");
 703  703          mdb_printf(OFFSTR "%-21H %s\n",
 704  704              OFFSET(ul_tmem),
 705  705              ulwp.ul_tmem.tm_size,
 706  706              prt_addr((void *)(addr + OFFSET(ul_tmem) + sizeof (size_t)), 0));
 707  707  
 708  708          return (DCMD_OK);
 709  709  }
 710  710  
 711  711  /*
 712  712   * Get the address of the unique uberdata_t structure.
 713  713   */
 714  714  static uintptr_t
 715  715  uberdata_addr(void)
 716  716  {
 717  717          uintptr_t uaddr;
 718  718          uintptr_t addr;
 719  719          GElf_Sym sym;
 720  720  
 721  721          if (mdb_lookup_by_obj("libc.so.1", "_tdb_bootstrap", &sym) != 0) {
 722  722                  mdb_warn("cannot find libc.so.1`_tdb_bootstrap");
 723  723                  return (NULL);
 724  724          }
 725  725          if (mdb_vread(&addr, sizeof (addr), sym.st_value) == sizeof (addr) &&
 726  726              addr != NULL &&
 727  727              mdb_vread(&uaddr, sizeof (uaddr), addr) == sizeof (uaddr) &&
 728  728              uaddr != NULL) {
 729  729                  return (uaddr);
 730  730          }
 731  731          if (mdb_lookup_by_obj("libc.so.1", "_uberdata", &sym) != 0) {
 732  732                  mdb_warn("cannot find libc.so.1`_uberdata");
 733  733                  return (NULL);
 734  734          }
 735  735          return ((uintptr_t)sym.st_value);
 736  736  }
 737  737  
 738  738  #undef OFFSET
 739  739  #define OFFSET(member)  ((size_t)OFFSETOF(uberdata_t, member))
 740  740  
 741  741  /*ARGSUSED*/
 742  742  static int
 743  743  d_uberdata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 744  744  {
 745  745          uberdata_t uberdata;
 746  746          int i;
 747  747  
 748  748          if (argc != 0)
 749  749                  return (DCMD_USAGE);
 750  750          if (!(flags & DCMD_ADDRSPEC) && (addr = uberdata_addr()) == NULL)
 751  751                  return (DCMD_ERR);
 752  752  
 753  753          if (mdb_vread(&uberdata, sizeof (uberdata), addr) !=
 754  754              sizeof (uberdata)) {
 755  755                  mdb_warn("failed to read uberdata at 0x%p", addr);
 756  756                  return (DCMD_ERR);
 757  757          }
 758  758  
 759  759          mdb_printf("%#a\n", addr);
 760  760  
 761  761          HD("&link_lock            &ld_lock              &fork_lock");
 762  762          mdb_printf(OFFSTR "%s %s %s\n",
 763  763              OFFSET(link_lock),
 764  764              prt_addr((void *)(addr + OFFSET(link_lock)), 1),
 765  765              prt_addr((void *)(addr + OFFSET(ld_lock)), 1),
 766  766              prt_addr((void *)(addr + OFFSET(fork_lock)), 0));
 767  767  
 768  768          HD("&atfork_lock          &callout_lock         &tdb_hash_lock");
 769  769          mdb_printf(OFFSTR "%s %s %s\n",
 770  770              OFFSET(atfork_lock),
 771  771              prt_addr((void *)(addr + OFFSET(atfork_lock)), 1),
 772  772              prt_addr((void *)(addr + OFFSET(callout_lock)), 1),
 773  773              prt_addr((void *)(addr + OFFSET(tdb_hash_lock)), 0));
 774  774  
 775  775          HD("&tdb_hash_lock_stats  &siguaction[0]");
 776  776          mdb_printf(OFFSTR "%s %s\n",
 777  777              OFFSET(tdb_hash_lock_stats),
 778  778              prt_addr((void *)(addr + OFFSET(tdb_hash_lock_stats)), 1),
 779  779              prt_addr((void *)(addr + OFFSET(siguaction)), 0));
 780  780  
 781  781          HD("&bucket               free_list             chunks");
 782  782          for (i = 0; i < NBUCKETS; i++) {
 783  783                  mdb_printf(OFFSTR "%s %s %ld\n",
 784  784                      OFFSET(bucket[i]),
 785  785                      prt_addr((void *)(addr + OFFSET(bucket[i])), 1),
 786  786                      prt_addr(uberdata.bucket[i].free_list, 1),
 787  787                      uberdata.bucket[i].chunks);
 788  788          }
 789  789  
 790  790          HD("&atexit_root          head                  exit_frame_monitor");
 791  791          mdb_printf(OFFSTR "%s %s %s\n",
 792  792              OFFSET(atexit_root),
 793  793              prt_addr((void *)(addr + OFFSET(atexit_root.exitfns_lock)), 1),
 794  794              prt_addr(uberdata.atexit_root.head, 1),
 795  795              prt_addr(uberdata.atexit_root.exit_frame_monitor, 0));
 796  796  
 797  797          HD("&quickexit_root       head");
 798  798          mdb_printf(OFFSTR "%s %s\n",
 799  799              OFFSET(quickexit_root),
 800  800              prt_addr((void *)(addr + OFFSET(quickexit_root.exitfns_lock)), 1),
 801  801              prt_addr(uberdata.quickexit_root.head, 0));
 802  802  
 803  803  
 804  804          HD("&tsd_metadata         tsdm_nkeys tsdm_nused tsdm_destro");
 805  805          mdb_printf(OFFSTR "%s %-10d %-10d %s\n",
 806  806              OFFSET(tsd_metadata),
 807  807              prt_addr((void *)(addr + OFFSET(tsd_metadata.tsdm_lock)), 1),
 808  808              uberdata.tsd_metadata.tsdm_nkeys,
 809  809              uberdata.tsd_metadata.tsdm_nused,
 810  810              prt_addr((void *)uberdata.tsd_metadata.tsdm_destro, 0));
 811  811  
 812  812          HD("&tls_metadata         tls_modinfo.data      tls_modinfo.size");
 813  813          mdb_printf(OFFSTR "%s %s %ld\n",
 814  814              OFFSET(tls_metadata),
 815  815              prt_addr((void *)(addr + OFFSET(tls_metadata.tls_lock)), 1),
 816  816              prt_addr(uberdata.tls_metadata.tls_modinfo.tls_data, 1),
 817  817              uberdata.tls_metadata.tls_modinfo.tls_size);
 818  818  
 819  819          HD("                      static_tls.data       static_tls.size");
 820  820          mdb_printf(OFFSTR "%s %s %ld\n",
 821  821              OFFSET(tls_metadata.static_tls),
 822  822              "                     ",
 823  823              prt_addr(uberdata.tls_metadata.static_tls.tls_data, 1),
 824  824              uberdata.tls_metadata.static_tls.tls_size);
 825  825  
 826  826          HD("primary_ma bucket_ini uflags.mt  uflags.pad uflags.trs uflags.ted");
 827  827          mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n",
 828  828              OFFSET(primary_map),
 829  829              uberdata.primary_map,
 830  830              uberdata.bucket_init,
 831  831              uberdata.uberflags.uf_x.x_mt,
 832  832              uberdata.uberflags.uf_x.x_pad,
 833  833              uberdata.uberflags.uf_x.x_tdb_register_sync,
 834  834              uberdata.uberflags.uf_x.x_thread_error_detection);
 835  835  
 836  836          HD("queue_head            thr_hash_table        hash_size  hash_mask");
 837  837          mdb_printf(OFFSTR "%s %s %-10d 0x%x\n",
 838  838              OFFSET(queue_head),
 839  839              prt_addr(uberdata.queue_head, 1),
 840  840              prt_addr(uberdata.thr_hash_table, 1),
 841  841              uberdata.hash_size,
 842  842              uberdata.hash_mask);
 843  843  
 844  844          HD("ulwp_one              all_lwps              all_zombies");
 845  845          mdb_printf(OFFSTR "%s %s %s\n",
 846  846              OFFSET(ulwp_one),
 847  847              prt_addr(uberdata.ulwp_one, 1),
 848  848              prt_addr(uberdata.all_lwps, 1),
 849  849              prt_addr(uberdata.all_zombies, 0));
 850  850  
 851  851          HD("nthreads   nzombies   ndaemons   pid");
 852  852          mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d\n",
 853  853              OFFSET(nthreads),
 854  854              uberdata.nthreads,
 855  855              uberdata.nzombies,
 856  856              uberdata.ndaemons,
 857  857              (int)uberdata.pid);
 858  858  
 859  859          HD("sigacthandler         setctxt");
 860  860          mdb_printf(OFFSTR "%s %s\n",
 861  861              OFFSET(sigacthandler),
 862  862              prt_addr((void *)uberdata.sigacthandler, 1),
 863  863              prt_addr((void *)uberdata.setctxt, 1));
 864  864  
 865  865          HD("lwp_stacks            lwp_laststack         nfreestack stk_cache");
 866  866          mdb_printf(OFFSTR "%s %s %-10d %d\n",
 867  867              OFFSET(lwp_stacks),
 868  868              prt_addr(uberdata.lwp_stacks, 1),
 869  869              prt_addr(uberdata.lwp_laststack, 1),
 870  870              uberdata.nfreestack,
 871  871              uberdata.thread_stack_cache);
 872  872  
 873  873          HD("ulwp_freelist         ulwp_lastfree         ulwp_replace_free");
 874  874          mdb_printf(OFFSTR "%s %s %s\n",
 875  875              OFFSET(ulwp_freelist),
 876  876              prt_addr(uberdata.ulwp_freelist, 1),
 877  877              prt_addr(uberdata.ulwp_lastfree, 1),
 878  878              prt_addr(uberdata.ulwp_replace_free, 0));
 879  879  
 880  880          HD("ulwp_replace_last     atforklist");
 881  881          mdb_printf(OFFSTR "%s %s\n",
 882  882              OFFSET(ulwp_replace_last),
 883  883              prt_addr(uberdata.ulwp_replace_last, 1),
 884  884              prt_addr(uberdata.atforklist, 0));
 885  885  
 886  886          HD("robustlocks           robustlist");
 887  887          mdb_printf(OFFSTR "%s %s\n",
 888  888              OFFSET(robustlocks),
 889  889              prt_addr(uberdata.robustlocks, 1),
 890  890              prt_addr(uberdata.robustlist, 1));
 891  891  
 892  892          HD("progname              ub_broot");
 893  893          mdb_printf(OFFSTR "%s %s\n",
 894  894              OFFSET(progname),
 895  895              prt_addr(uberdata.progname, 1),
 896  896              prt_addr(uberdata.ub_broot, 1));
 897  897  
 898  898          HD("tdb_bootstrap         tdb_sync_addr_hash    tdb_'count tdb_'fail");
 899  899          mdb_printf(OFFSTR "%s %s %-10d %d\n",
 900  900              OFFSET(tdb_bootstrap),
 901  901              prt_addr(uberdata.tdb_bootstrap, 1),
 902  902              prt_addr(uberdata.tdb.tdb_sync_addr_hash, 1),
 903  903              uberdata.tdb.tdb_register_count,
 904  904              uberdata.tdb.tdb_hash_alloc_failed);
 905  905  
 906  906          HD("tdb_sync_addr_free    tdb_sync_addr_last    tdb_sync_alloc");
 907  907          mdb_printf(OFFSTR "%s %s %ld\n",
 908  908              OFFSET(tdb.tdb_sync_addr_free),
 909  909              prt_addr(uberdata.tdb.tdb_sync_addr_free, 1),
 910  910              prt_addr(uberdata.tdb.tdb_sync_addr_last, 1),
 911  911              uberdata.tdb.tdb_sync_alloc);
 912  912  
 913  913          HD("tdb_ev_global_mask    tdb_events");
 914  914          mdb_printf(OFFSTR "0x%08x 0x%08x %s\n",
 915  915              OFFSET(tdb.tdb_ev_global_mask),
 916  916              uberdata.tdb.tdb_ev_global_mask.event_bits[0],
 917  917              uberdata.tdb.tdb_ev_global_mask.event_bits[1],
 918  918              prt_addr((void *)uberdata.tdb.tdb_events, 0));
 919  919  
 920  920          return (DCMD_OK);
 921  921  }
 922  922  
 923  923  static int
 924  924  ulwp_walk_init(mdb_walk_state_t *wsp)
 925  925  {
 926  926          uintptr_t addr = wsp->walk_addr;
 927  927          uintptr_t uber_addr;
 928  928  
 929  929          if (addr == NULL &&
 930  930              ((uber_addr = uberdata_addr()) == NULL ||
 931  931              mdb_vread(&addr, sizeof (addr),
 932  932              uber_addr + OFFSETOF(uberdata_t, all_lwps))
 933  933              != sizeof (addr))) {
 934  934                  mdb_warn("cannot find 'uberdata.all_lwps'");
 935  935                  return (WALK_ERR);
 936  936          }
 937  937          if (addr == NULL)
 938  938                  return (WALK_DONE);
 939  939          wsp->walk_addr = addr;
 940  940          wsp->walk_data = (void *)addr;
 941  941          return (WALK_NEXT);
 942  942  }
 943  943  
 944  944  static int
 945  945  ulwp_walk_step(mdb_walk_state_t *wsp)
 946  946  {
 947  947          uintptr_t addr = wsp->walk_addr;
 948  948          ulwp_t ulwp;
 949  949  
 950  950          if (addr == NULL)
 951  951                  return (WALK_DONE);
 952  952          if (mdb_vread(&ulwp, sizeof (ulwp), addr) != sizeof (ulwp) &&
 953  953              (bzero(&ulwp, sizeof (ulwp)),
 954  954              mdb_vread(&ulwp, REPLACEMENT_SIZE, addr)) != REPLACEMENT_SIZE) {
 955  955                  mdb_warn("failed to read ulwp at 0x%p", addr);
 956  956                  return (WALK_ERR);
 957  957          }
 958  958          /*
 959  959           * If we have looped around to the beginning
 960  960           * of the circular linked list, we are done.
 961  961           */
 962  962          if ((wsp->walk_addr = (uintptr_t)ulwp.ul_forw)
 963  963              == (uintptr_t)wsp->walk_data)
 964  964                  wsp->walk_addr = NULL;
 965  965          return (wsp->walk_callback(addr, &ulwp, wsp->walk_cbdata));
 966  966  }
 967  967  
 968  968  /* Avoid classifying NULL pointers as part of the main stack on x86 */
 969  969  #define MIN_STACK_ADDR          (0x10000ul)
 970  970  
 971  971  static int
 972  972  whatis_walk_ulwp(uintptr_t addr, const ulwp_t *ulwp, mdb_whatis_t *w)
 973  973  {
 974  974          uintptr_t cur;
 975  975          lwpid_t id = ulwp->ul_lwpid;
 976  976          uintptr_t top, base, size;
 977  977  
 978  978          while (mdb_whatis_match(w, addr, sizeof (ulwp_t), &cur))
 979  979                  mdb_whatis_report_object(w, cur, addr,
 980  980                      "allocated as thread %#r's ulwp_t\n", id);
 981  981  
 982  982          top = (uintptr_t)ulwp->ul_stktop;
 983  983          size = ulwp->ul_stksiz;
 984  984  
 985  985          /*
 986  986           * The main stack ends up being a little weird, especially if
 987  987           * the stack ulimit is unlimited.  This tries to take that into
 988  988           * account.
 989  989           */
 990  990          if (size > top)
 991  991                  size = top;
 992  992          if (top > MIN_STACK_ADDR && top - size < MIN_STACK_ADDR)
 993  993                  size = top - MIN_STACK_ADDR;
 994  994  
 995  995          base = top - size;
 996  996  
 997  997          while (mdb_whatis_match(w, base, size, &cur))
 998  998                  mdb_whatis_report_address(w, cur, "in [ stack tid=%#r ]\n", id);
 999  999  
1000 1000          if (ulwp->ul_ustack.ss_flags & SS_ONSTACK) {
1001 1001                  base = (uintptr_t)ulwp->ul_ustack.ss_sp;
1002 1002                  size = ulwp->ul_ustack.ss_size;
1003 1003  
1004 1004                  while (mdb_whatis_match(w, base, size, &cur))
1005 1005                          mdb_whatis_report_address(w, cur,
1006 1006                              "in [ altstack tid=%#r ]\n", id);
1007 1007          }
1008 1008  
1009 1009          return (WHATIS_WALKRET(w));
1010 1010  }
1011 1011  
1012 1012  /*ARGSUSED*/
1013 1013  static int
1014 1014  whatis_run_ulwps(mdb_whatis_t *w, void *arg)
1015 1015  {
1016 1016          if (mdb_walk("ulwps", (mdb_walk_cb_t)whatis_walk_ulwp, w) == -1) {
1017 1017                  mdb_warn("couldn't find ulwps walker");
1018 1018                  return (1);
1019 1019          }
1020 1020          return (0);
1021 1021  }
1022 1022  
1023 1023  /*
1024 1024   * =======================================================
1025 1025   * End of thread (previously libthread) interfaces.
1026 1026   * ==================== threads ==========================
1027 1027   */
1028 1028  
1029 1029  int
1030 1030  stacks_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1031 1031  {
1032 1032          int rval = stacks(addr, flags, argc, argv);
1033 1033  
1034 1034          /*
1035 1035           * For the user-level variant of ::stacks, we don't bother caching
1036 1036           * state, as even a very large program is unlikely to compare to the
1037 1037           * kernel in terms of number of threads.  (And if you find yourself
1038 1038           * here in anger, frustrated about how long ::stacks is running on
1039 1039           * your galactically complicated zillion-thread program, hopefully
1040 1040           * you will find some solace in the irony.  Okay, probably not...)
1041 1041           */
1042 1042          stacks_cleanup(B_TRUE);
1043 1043          return (rval);
1044 1044  }
1045 1045  
1046 1046  typedef struct tid2ulwp_walk {
1047 1047          lwpid_t t2u_tid;
1048 1048          uintptr_t t2u_lwp;
1049 1049          boolean_t t2u_found;
1050 1050  } tid2ulwp_walk_t;
1051 1051  
1052 1052  /*ARGSUSED*/
1053 1053  static int
1054 1054  tid2ulwp_walk(uintptr_t addr, ulwp_t *ulwp, tid2ulwp_walk_t *t2u)
1055 1055  {
1056 1056          if (ulwp->ul_lwpid == t2u->t2u_tid) {
1057 1057                  t2u->t2u_lwp = addr;
1058 1058                  t2u->t2u_found = B_TRUE;
1059 1059                  return (WALK_DONE);
1060 1060          }
1061 1061  
1062 1062          return (WALK_NEXT);
1063 1063  }
1064 1064  
1065 1065  static int
1066 1066  tid2ulwp_impl(uintptr_t tid_addr, uintptr_t *ulwp_addrp)
1067 1067  {
1068 1068          tid2ulwp_walk_t t2u;
1069 1069  
1070 1070          bzero(&t2u, sizeof (t2u));
1071 1071          t2u.t2u_tid = (lwpid_t)tid_addr;
1072 1072  
1073 1073          if (mdb_walk("ulwp", (mdb_walk_cb_t)tid2ulwp_walk, &t2u) != 0) {
1074 1074                  mdb_warn("can't walk 'ulwp'");
1075 1075                  return (DCMD_ERR);
1076 1076          }
1077 1077  
1078 1078          if (!t2u.t2u_found) {
1079 1079                  mdb_warn("thread ID %d not found", t2u.t2u_tid);
1080 1080                  return (DCMD_ERR);
1081 1081          }
1082 1082          *ulwp_addrp = t2u.t2u_lwp;
1083 1083          return (DCMD_OK);
1084 1084  }
1085 1085  
1086 1086  /*ARGSUSED*/
1087 1087  static int
1088 1088  tid2ulwp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1089 1089  {
1090 1090          uintptr_t ulwp_addr;
1091 1091          int error;
1092 1092  
1093 1093          if (argc != 0)
1094 1094                  return (DCMD_USAGE);
1095 1095  
1096 1096          error = tid2ulwp_impl(addr, &ulwp_addr);
1097 1097          if (error == DCMD_OK)
1098 1098                  mdb_printf("%p\n", ulwp_addr);
1099 1099          return (error);
1100 1100  }
1101 1101  
1102 1102  typedef struct mdb_libc_ulwp {
1103 1103          void *ul_ftsd[TSD_NFAST];
1104 1104          tsd_t *ul_stsd;
1105 1105  } mdb_libc_ulwp_t;
1106 1106  
1107 1107  /*
1108 1108   * Map from thread pointer to tsd for given key
1109 1109   */
1110 1110  static int
1111 1111  d_tsd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1112 1112  {
1113 1113          mdb_libc_ulwp_t u;
1114 1114          uintptr_t ulwp_addr;
1115 1115          uintptr_t key = NULL;
1116 1116          void *element = NULL;
1117 1117  
1118 1118          if (mdb_getopts(argc, argv, 'k', MDB_OPT_UINTPTR, &key, NULL) != argc)
1119 1119                  return (DCMD_USAGE);
1120 1120  
1121 1121          if (!(flags & DCMD_ADDRSPEC) || key == NULL)
1122 1122                  return (DCMD_USAGE);
1123 1123  
1124 1124          if (tid2ulwp_impl(addr, &ulwp_addr) != DCMD_OK)
1125 1125                  return (DCMD_ERR);
1126 1126  
1127 1127          if (mdb_ctf_vread(&u, "ulwp_t", "mdb_libc_ulwp_t", ulwp_addr, 0) == -1)
1128 1128                  return (DCMD_ERR);
1129 1129  
1130 1130          if (key < TSD_NFAST) {
1131 1131                  element = u.ul_ftsd[key];
1132 1132          } else if (u.ul_stsd != NULL) {
1133 1133                  uint_t nalloc;
1134 1134                  /* tsd_t is a union, so we can't use ctf_vread() on it. */
1135 1135                  if (mdb_vread(&nalloc, sizeof (nalloc),
1136 1136                      (uintptr_t)&u.ul_stsd->tsd_nalloc) == -1) {
1137 1137                          mdb_warn("failed to read tsd_t at %p", u.ul_stsd);
1138 1138                          return (DCMD_ERR);
1139 1139                  }
1140 1140                  if (key < nalloc) {
1141 1141                          if (mdb_vread(&element, sizeof (element),
1142 1142                              (uintptr_t)&u.ul_stsd->tsd_data[key]) == -1) {
1143 1143                                  mdb_warn("failed to read tsd_t at %p",
1144 1144                                      u.ul_stsd);
1145 1145                                  return (DCMD_ERR);
1146 1146                          }
1147 1147                  }
1148 1148          }
1149 1149  
1150 1150          if (element == NULL && (flags & DCMD_PIPE))
1151 1151                  return (DCMD_OK);
1152 1152  
1153 1153          mdb_printf("%p\n", element);
1154 1154          return (DCMD_OK);
1155 1155  }
1156 1156  
1157 1157  static const mdb_dcmd_t dcmds[] = {
1158 1158          { "jmp_buf", ":", "print jmp_buf contents", d_jmp_buf, NULL },
1159 1159          { "sigjmp_buf", ":", "print sigjmp_buf contents", d_sigjmp_buf, NULL },
1160 1160          { "siginfo", ":", "print siginfo_t structure", d_siginfo, NULL },
1161 1161          { "stacks", "?[-afiv] [-c func] [-C func] [-m module] [-M module] ",
1162 1162                  "print unique thread stacks", stacks_dcmd, stacks_help },
1163 1163          { "tid2ulwp", "?", "convert TID to ulwp_t address", tid2ulwp },
1164 1164          { "ucontext", ":", "print ucontext_t structure", d_ucontext, NULL },
1165 1165          { "ulwp", ":", "print ulwp_t structure", d_ulwp, NULL },
1166 1166          { "uberdata", ":", "print uberdata_t structure", d_uberdata, NULL },
1167 1167          { "tsd", ":-k key", "print tsd for this thread", d_tsd, NULL },
1168 1168          { NULL }
1169 1169  };
1170 1170  
1171 1171  static const mdb_walker_t walkers[] = {
1172 1172          { "ucontext", "walk ucontext_t uc_link list",
1173 1173                  NULL, uc_walk_step, NULL, NULL },
1174 1174          { "oldcontext", "walk per-lwp oldcontext pointers",
1175 1175                  oldc_walk_init, oldc_walk_step, oldc_walk_fini, NULL },
1176 1176          { "ulwps", "walk list of ulwp_t pointers",
1177 1177                  ulwp_walk_init, ulwp_walk_step, NULL, NULL },
1178 1178          { "ulwp", "walk list of ulwp_t pointers",
1179 1179                  ulwp_walk_init, ulwp_walk_step, NULL, NULL },
1180 1180          { NULL }
1181 1181  };
1182 1182  
1183 1183  static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
1184 1184  
1185 1185  const mdb_modinfo_t *
1186 1186  _mdb_init(void)
1187 1187  {
1188 1188          mdb_whatis_register("threads", whatis_run_ulwps, NULL,
1189 1189              WHATIS_PRIO_EARLY, WHATIS_REG_NO_ID);
1190 1190  
1191 1191          return (&modinfo);
1192 1192  }
  
    | 
      ↓ open down ↓ | 
    1192 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX