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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 /*
  26  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
  27  * Copyright (c) 2018, Joyent, Inc.
  28  */
  29 
  30 
  31 #include <mdb/mdb_modapi.h>
  32 #include <mdb/mdb_ks.h>
  33 #include <mdb/mdb_ctf.h>
  34 #include <sys/types.h>
  35 #include <sys/thread.h>
  36 #include <sys/lwp.h>
  37 #include <sys/proc.h>
  38 #include <sys/cpuvar.h>
  39 #include <sys/cpupart.h>
  40 #include <sys/disp.h>
  41 #include <sys/taskq_impl.h>
  42 #include <sys/stack.h>
  43 #include "thread.h"
  44 
  45 #ifndef STACK_BIAS
  46 #define STACK_BIAS      0
  47 #endif
  48 
  49 typedef struct thread_walk {
  50         kthread_t *tw_thread;
  51         uintptr_t tw_last;
  52         uint_t tw_inproc;
  53         uint_t tw_step;
  54 } thread_walk_t;
  55 
  56 int
  57 thread_walk_init(mdb_walk_state_t *wsp)
  58 {
  59         thread_walk_t *twp = mdb_alloc(sizeof (thread_walk_t), UM_SLEEP);
  60 
  61         if (wsp->walk_addr == NULL) {
  62                 if (mdb_readvar(&wsp->walk_addr, "allthreads") == -1) {
  63                         mdb_warn("failed to read 'allthreads'");
  64                         mdb_free(twp, sizeof (thread_walk_t));
  65                         return (WALK_ERR);
  66                 }
  67 
  68                 twp->tw_inproc = FALSE;
  69 
  70         } else {
  71                 proc_t pr;
  72 
  73                 if (mdb_vread(&pr, sizeof (proc_t), wsp->walk_addr) == -1) {
  74                         mdb_warn("failed to read proc at %p", wsp->walk_addr);
  75                         mdb_free(twp, sizeof (thread_walk_t));
  76                         return (WALK_ERR);
  77                 }
  78 
  79                 wsp->walk_addr = (uintptr_t)pr.p_tlist;
  80                 twp->tw_inproc = TRUE;
  81         }
  82 
  83         twp->tw_thread = mdb_alloc(sizeof (kthread_t), UM_SLEEP);
  84         twp->tw_last = wsp->walk_addr;
  85         twp->tw_step = FALSE;
  86 
  87         wsp->walk_data = twp;
  88         return (WALK_NEXT);
  89 }
  90 
  91 int
  92 thread_walk_step(mdb_walk_state_t *wsp)
  93 {
  94         thread_walk_t *twp = (thread_walk_t *)wsp->walk_data;
  95         int status;
  96 
  97         if (wsp->walk_addr == NULL)
  98                 return (WALK_DONE); /* Proc has 0 threads or allthreads = 0 */
  99 
 100         if (twp->tw_step && wsp->walk_addr == twp->tw_last)
 101                 return (WALK_DONE); /* We've wrapped around */
 102 
 103         if (mdb_vread(twp->tw_thread, sizeof (kthread_t),
 104             wsp->walk_addr) == -1) {
 105                 mdb_warn("failed to read thread at %p", wsp->walk_addr);
 106                 return (WALK_DONE);
 107         }
 108 
 109         status = wsp->walk_callback(wsp->walk_addr, twp->tw_thread,
 110             wsp->walk_cbdata);
 111 
 112         if (twp->tw_inproc)
 113                 wsp->walk_addr = (uintptr_t)twp->tw_thread->t_forw;
 114         else
 115                 wsp->walk_addr = (uintptr_t)twp->tw_thread->t_next;
 116 
 117         twp->tw_step = TRUE;
 118         return (status);
 119 }
 120 
 121 void
 122 thread_walk_fini(mdb_walk_state_t *wsp)
 123 {
 124         thread_walk_t *twp = (thread_walk_t *)wsp->walk_data;
 125 
 126         mdb_free(twp->tw_thread, sizeof (kthread_t));
 127         mdb_free(twp, sizeof (thread_walk_t));
 128 }
 129 
 130 int
 131 deathrow_walk_init(mdb_walk_state_t *wsp)
 132 {
 133         if (mdb_layered_walk("thread_deathrow", wsp) == -1) {
 134                 mdb_warn("couldn't walk 'thread_deathrow'");
 135                 return (WALK_ERR);
 136         }
 137 
 138         if (mdb_layered_walk("lwp_deathrow", wsp) == -1) {
 139                 mdb_warn("couldn't walk 'lwp_deathrow'");
 140                 return (WALK_ERR);
 141         }
 142 
 143         return (WALK_NEXT);
 144 }
 145 
 146 int
 147 deathrow_walk_step(mdb_walk_state_t *wsp)
 148 {
 149         kthread_t t;
 150         uintptr_t addr = wsp->walk_addr;
 151 
 152         if (addr == NULL)
 153                 return (WALK_DONE);
 154 
 155         if (mdb_vread(&t, sizeof (t), addr) == -1) {
 156                 mdb_warn("couldn't read deathrow thread at %p", addr);
 157                 return (WALK_ERR);
 158         }
 159 
 160         wsp->walk_addr = (uintptr_t)t.t_forw;
 161 
 162         return (wsp->walk_callback(addr, &t, wsp->walk_cbdata));
 163 }
 164 
 165 int
 166 thread_deathrow_walk_init(mdb_walk_state_t *wsp)
 167 {
 168         if (mdb_readvar(&wsp->walk_addr, "thread_deathrow") == -1) {
 169                 mdb_warn("couldn't read symbol 'thread_deathrow'");
 170                 return (WALK_ERR);
 171         }
 172 
 173         return (WALK_NEXT);
 174 }
 175 
 176 int
 177 lwp_deathrow_walk_init(mdb_walk_state_t *wsp)
 178 {
 179         if (mdb_readvar(&wsp->walk_addr, "lwp_deathrow") == -1) {
 180                 mdb_warn("couldn't read symbol 'lwp_deathrow'");
 181                 return (WALK_ERR);
 182         }
 183 
 184         return (WALK_NEXT);
 185 }
 186 
 187 
 188 typedef struct dispq_walk {
 189         int dw_npri;
 190         uintptr_t dw_dispq;
 191         uintptr_t dw_last;
 192 } dispq_walk_t;
 193 
 194 int
 195 cpu_dispq_walk_init(mdb_walk_state_t *wsp)
 196 {
 197         uintptr_t addr = wsp->walk_addr;
 198         dispq_walk_t *dw;
 199         cpu_t cpu;
 200         dispq_t dispq;
 201         disp_t disp;
 202 
 203         if (addr == NULL) {
 204                 mdb_warn("cpu_dispq walk needs a cpu_t address\n");
 205                 return (WALK_ERR);
 206         }
 207 
 208         if (mdb_vread(&cpu, sizeof (cpu_t), addr) == -1) {
 209                 mdb_warn("failed to read cpu_t at %p", addr);
 210                 return (WALK_ERR);
 211         }
 212 
 213         if (mdb_vread(&disp, sizeof (disp_t), (uintptr_t)cpu.cpu_disp) == -1) {
 214                 mdb_warn("failed to read disp_t at %p", cpu.cpu_disp);
 215                 return (WALK_ERR);
 216         }
 217 
 218         if (mdb_vread(&dispq, sizeof (dispq_t),
 219             (uintptr_t)disp.disp_q) == -1) {
 220                 mdb_warn("failed to read dispq_t at %p", disp.disp_q);
 221                 return (WALK_ERR);
 222         }
 223 
 224         dw = mdb_alloc(sizeof (dispq_walk_t), UM_SLEEP);
 225 
 226         dw->dw_npri = disp.disp_npri;
 227         dw->dw_dispq = (uintptr_t)disp.disp_q;
 228         dw->dw_last = (uintptr_t)dispq.dq_last;
 229 
 230         wsp->walk_addr = (uintptr_t)dispq.dq_first;
 231         wsp->walk_data = dw;
 232 
 233         return (WALK_NEXT);
 234 }
 235 
 236 int
 237 cpupart_dispq_walk_init(mdb_walk_state_t *wsp)
 238 {
 239         uintptr_t addr = wsp->walk_addr;
 240         dispq_walk_t *dw;
 241         cpupart_t cpupart;
 242         dispq_t dispq;
 243 
 244         if (addr == NULL) {
 245                 mdb_warn("cpupart_dispq walk needs a cpupart_t address\n");
 246                 return (WALK_ERR);
 247         }
 248 
 249         if (mdb_vread(&cpupart, sizeof (cpupart_t), addr) == -1) {
 250                 mdb_warn("failed to read cpupart_t at %p", addr);
 251                 return (WALK_ERR);
 252         }
 253 
 254         if (mdb_vread(&dispq, sizeof (dispq_t),
 255             (uintptr_t)cpupart.cp_kp_queue.disp_q) == -1) {
 256                 mdb_warn("failed to read dispq_t at %p",
 257                     cpupart.cp_kp_queue.disp_q);
 258                 return (WALK_ERR);
 259         }
 260 
 261         dw = mdb_alloc(sizeof (dispq_walk_t), UM_SLEEP);
 262 
 263         dw->dw_npri = cpupart.cp_kp_queue.disp_npri;
 264         dw->dw_dispq = (uintptr_t)cpupart.cp_kp_queue.disp_q;
 265         dw->dw_last = (uintptr_t)dispq.dq_last;
 266 
 267         wsp->walk_addr = (uintptr_t)dispq.dq_first;
 268         wsp->walk_data = dw;
 269 
 270         return (WALK_NEXT);
 271 }
 272 
 273 int
 274 dispq_walk_step(mdb_walk_state_t *wsp)
 275 {
 276         uintptr_t addr = wsp->walk_addr;
 277         dispq_walk_t *dw = wsp->walk_data;
 278         dispq_t dispq;
 279         kthread_t t;
 280 
 281         while (addr == NULL) {
 282                 if (--dw->dw_npri == 0)
 283                         return (WALK_DONE);
 284 
 285                 dw->dw_dispq += sizeof (dispq_t);
 286 
 287                 if (mdb_vread(&dispq, sizeof (dispq_t), dw->dw_dispq) == -1) {
 288                         mdb_warn("failed to read dispq_t at %p", dw->dw_dispq);
 289                         return (WALK_ERR);
 290                 }
 291 
 292                 dw->dw_last = (uintptr_t)dispq.dq_last;
 293                 addr = (uintptr_t)dispq.dq_first;
 294         }
 295 
 296         if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {
 297                 mdb_warn("failed to read kthread_t at %p", addr);
 298                 return (WALK_ERR);
 299         }
 300 
 301         if (addr == dw->dw_last)
 302                 wsp->walk_addr = NULL;
 303         else
 304                 wsp->walk_addr = (uintptr_t)t.t_link;
 305 
 306         return (wsp->walk_callback(addr, &t, wsp->walk_cbdata));
 307 }
 308 
 309 void
 310 dispq_walk_fini(mdb_walk_state_t *wsp)
 311 {
 312         mdb_free(wsp->walk_data, sizeof (dispq_walk_t));
 313 }
 314 
 315 struct thread_state {
 316         uint_t ts_state;
 317         const char *ts_name;
 318 } thread_states[] = {
 319         { TS_FREE,      "free" },
 320         { TS_SLEEP,     "sleep" },
 321         { TS_RUN,       "run" },
 322         { TS_ONPROC,    "onproc" },
 323         { TS_ZOMB,      "zomb" },
 324         { TS_STOPPED,   "stopped" },
 325         { TS_WAIT,      "wait" }
 326 };
 327 #define NUM_THREAD_STATES (sizeof (thread_states) / sizeof (*thread_states))
 328 
 329 void
 330 thread_state_to_text(uint_t state, char *out, size_t out_sz)
 331 {
 332         int idx;
 333 
 334         for (idx = 0; idx < NUM_THREAD_STATES; idx++) {
 335                 struct thread_state *tsp = &thread_states[idx];
 336                 if (tsp->ts_state == state) {
 337                         mdb_snprintf(out, out_sz, "%s", tsp->ts_name);
 338                         return;
 339                 }
 340         }
 341         mdb_snprintf(out, out_sz, "inval/%02x", state);
 342 }
 343 
 344 int
 345 thread_text_to_state(const char *state, uint_t *out)
 346 {
 347         int idx;
 348 
 349         for (idx = 0; idx < NUM_THREAD_STATES; idx++) {
 350                 struct thread_state *tsp = &thread_states[idx];
 351                 if (strcasecmp(tsp->ts_name, state) == 0) {
 352                         *out = tsp->ts_state;
 353                         return (0);
 354                 }
 355         }
 356         return (-1);
 357 }
 358 
 359 void
 360 thread_walk_states(void (*cbfunc)(uint_t, const char *, void *), void *cbarg)
 361 {
 362         int idx;
 363 
 364         for (idx = 0; idx < NUM_THREAD_STATES; idx++) {
 365                 struct thread_state *tsp = &thread_states[idx];
 366                 cbfunc(tsp->ts_state, tsp->ts_name, cbarg);
 367         }
 368 }
 369 
 370 #define TF_INTR         0x01
 371 #define TF_PROC         0x02
 372 #define TF_BLOCK        0x04
 373 #define TF_SIG          0x08
 374 #define TF_DISP         0x10
 375 #define TF_MERGE        0x20
 376 
 377 /*
 378  * Display a kthread_t.
 379  * This is a little complicated, as there is a lot of information that
 380  * the user could be interested in.  The flags "ipbsd" are used to
 381  * indicate which subset of the thread's members are to be displayed
 382  * ('i' is the default).  If multiple options are specified, multiple
 383  * sets of data will be displayed in a vaguely readable format.  If the
 384  * 'm' option is specified, all the selected sets will be merged onto a
 385  * single line for the benefit of those using wider-than-normal
 386  * terminals.  Having a generic mechanism for doing this would be
 387  * really useful, but is a project best left to another day.
 388  */
 389 
 390 int
 391 thread(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 392 {
 393         kthread_t       t;
 394         uint_t          oflags = 0;
 395         uint_t          fflag = FALSE;
 396         int             first;
 397         char            stbuf[20];
 398 
 399         /*
 400          * "Gracefully" handle printing a boatload of stuff to the
 401          * screen.  If we are not printing our first set of data, and
 402          * we haven't been instructed to merge sets together, output a
 403          * newline and indent such that the thread addresses form a
 404          * column of their own.
 405          */
 406 #define SPACER()                                \
 407         if (first) {                            \
 408                 first = FALSE;                  \
 409         } else if (!(oflags & TF_MERGE)) {  \
 410                 mdb_printf("\n%?s", "");        \
 411         }
 412 
 413         if (!(flags & DCMD_ADDRSPEC)) {
 414                 if (mdb_walk_dcmd("thread", "thread", argc, argv) == -1) {
 415                         mdb_warn("can't walk threads");
 416                         return (DCMD_ERR);
 417                 }
 418                 return (DCMD_OK);
 419         }
 420 
 421         if (mdb_getopts(argc, argv,
 422             'f', MDB_OPT_SETBITS, TRUE, &fflag,
 423             'i', MDB_OPT_SETBITS, TF_INTR, &oflags,
 424             'p', MDB_OPT_SETBITS, TF_PROC, &oflags,
 425             'b', MDB_OPT_SETBITS, TF_BLOCK, &oflags,
 426             's', MDB_OPT_SETBITS, TF_SIG, &oflags,
 427             'd', MDB_OPT_SETBITS, TF_DISP, &oflags,
 428             'm', MDB_OPT_SETBITS, TF_MERGE, &oflags, NULL) != argc)
 429                 return (DCMD_USAGE);
 430 
 431         /*
 432          * If no sets were specified, choose the 'i' set.
 433          */
 434         if (!(oflags & ~TF_MERGE))
 435 #ifdef  _LP64
 436                 oflags = TF_INTR;
 437 #else
 438                 oflags = TF_INTR | TF_DISP | TF_MERGE;
 439 #endif
 440 
 441         /*
 442          * Print the relevant headers; note use of SPACER().
 443          */
 444         if (DCMD_HDRSPEC(flags)) {
 445                 first = TRUE;
 446                 mdb_printf("%<u>%?s%</u>", "ADDR");
 447                 mdb_flush();
 448 
 449                 if (oflags & TF_PROC) {
 450                         SPACER();
 451                         mdb_printf("%<u> %?s %?s %?s%</u>",
 452                             "PROC", "LWP", "CRED");
 453                 }
 454 
 455                 if (oflags & TF_INTR) {
 456                         SPACER();
 457                         mdb_printf("%<u> %8s %4s %4s %4s %5s %5s %3s %?s%</u>",
 458                             "STATE", "FLG", "PFLG",
 459                             "SFLG", "PRI", "EPRI", "PIL", "INTR");
 460                 }
 461 
 462                 if (oflags & TF_BLOCK) {
 463                         SPACER();
 464                         mdb_printf("%<u> %?s %?s %?s %11s%</u>",
 465                             "WCHAN", "TS", "PITS", "SOBJ OPS");
 466                 }
 467 
 468                 if (oflags & TF_SIG) {
 469                         SPACER();
 470                         mdb_printf("%<u> %?s %16s %16s%</u>",
 471                             "SIGQUEUE", "SIG PEND", "SIG HELD");
 472                 }
 473 
 474                 if (oflags & TF_DISP) {
 475                         SPACER();
 476                         mdb_printf("%<u> %?s %5s %2s %-6s%</u>",
 477                             "DISPTIME", "BOUND", "PR", "SWITCH");
 478                 }
 479                 mdb_printf("\n");
 480         }
 481 
 482         if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {
 483                 mdb_warn("can't read kthread_t at %#lx", addr);
 484                 return (DCMD_ERR);
 485         }
 486 
 487         if (fflag && (t.t_state == TS_FREE))
 488                 return (DCMD_OK);
 489 
 490         first = TRUE;
 491         mdb_printf("%0?lx", addr);
 492 
 493         /* process information */
 494         if (oflags & TF_PROC) {
 495                 SPACER();
 496                 mdb_printf(" %?p %?p %?p", t.t_procp, t.t_lwp, t.t_cred);
 497         }
 498 
 499         /* priority/interrupt information */
 500         if (oflags & TF_INTR) {
 501                 SPACER();
 502                 thread_state_to_text(t.t_state, stbuf, sizeof (stbuf));
 503                 if (t.t_intr == NULL) {
 504                         mdb_printf(" %-8s %4x %4x %4x %5d %5d %3d %?s",
 505                             stbuf, t.t_flag, t.t_proc_flag, t.t_schedflag,
 506                             t.t_pri, t.t_epri, t.t_pil, "n/a");
 507                 } else {
 508                         mdb_printf(" %-8s %4x %4x %4x %5d %5d %3d %?p",
 509                             stbuf, t.t_flag, t.t_proc_flag, t.t_schedflag,
 510                             t.t_pri, t.t_epri, t.t_pil, t.t_intr);
 511                 }
 512         }
 513 
 514         /* blocking information */
 515         if (oflags & TF_BLOCK) {
 516                 SPACER();
 517                 (void) mdb_snprintf(stbuf, 20, "%a", t.t_sobj_ops);
 518                 stbuf[11] = '\0';
 519                 mdb_printf(" %?p %?p %?p %11s",
 520                     t.t_wchan, t.t_ts, t.t_prioinv, stbuf);
 521         }
 522 
 523         /* signal information */
 524         if (oflags & TF_SIG) {
 525                 SPACER();
 526                 mdb_printf(" %?p %016llx %016llx",
 527                     t.t_sigqueue, t.t_sig, t.t_hold);
 528         }
 529 
 530         /* dispatcher stuff */
 531         if (oflags & TF_DISP) {
 532                 SPACER();
 533                 mdb_printf(" %?lx %5d %2d ",
 534                     t.t_disp_time, t.t_bind_cpu, t.t_preempt);
 535                 if (t.t_disp_time != 0)
 536                         mdb_printf("t-%-4d",
 537                             (clock_t)mdb_get_lbolt() - t.t_disp_time);
 538                 else
 539                         mdb_printf("%-6s", "-");
 540         }
 541 
 542         mdb_printf("\n");
 543 
 544 #undef SPACER
 545 
 546         return (DCMD_OK);
 547 }
 548 
 549 void
 550 thread_help(void)
 551 {
 552         mdb_printf(
 553             "The flags -ipbsd control which information is displayed.  When\n"
 554             "combined, the fields are displayed on separate lines unless the\n"
 555             "-m option is given.\n"
 556             "\n"
 557             "\t-b\tprint blocked thread state\n"
 558             "\t-d\tprint dispatcher state\n"
 559             "\t-f\tignore freed threads\n"
 560             "\t-i\tprint basic thread state (default)\n"
 561             "\t-m\tdisplay results on a single line\n"
 562             "\t-p\tprint process and lwp state\n"
 563             "\t-s\tprint signal state\n");
 564 }
 565 
 566 /*
 567  * Return a string description of the thread, including the ID and the thread
 568  * name.
 569  *
 570  * If ->t_name is NULL, and we're a system thread, we'll do a little more
 571  * spelunking to find a useful string to return.
 572  */
 573 int
 574 thread_getdesc(uintptr_t addr, boolean_t include_comm,
 575     char *buf, size_t bufsize)
 576 {
 577         char name[THREAD_NAME_MAX] = "";
 578         kthread_t t;
 579         proc_t p;
 580 
 581         bzero(buf, bufsize);
 582 
 583         if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {
 584                 mdb_warn("failed to read kthread_t at %p", addr);
 585                 return (-1);
 586         }
 587 
 588         if (t.t_tid == 0) {
 589                 taskq_t tq;
 590 
 591                 if (mdb_vread(&tq, sizeof (taskq_t),
 592                     (uintptr_t)t.t_taskq) == -1)
 593                         tq.tq_name[0] = '\0';
 594 
 595                 if (t.t_name != NULL) {
 596                         if (mdb_readstr(buf, bufsize,
 597                             (uintptr_t)t.t_name) == -1) {
 598                                 mdb_warn("error reading thread name");
 599                         }
 600                 } else if (tq.tq_name[0] != '\0') {
 601                         (void) mdb_snprintf(buf, bufsize, "tq:%s", tq.tq_name);
 602                 } else {
 603                         mdb_snprintf(buf, bufsize, "%a()", t.t_startpc);
 604                 }
 605 
 606                 return (buf[0] == '\0' ? -1 : 0);
 607         }
 608 
 609         if (include_comm && mdb_vread(&p, sizeof (proc_t),
 610             (uintptr_t)t.t_procp) == -1) {
 611                 mdb_warn("failed to read proc at %p", t.t_procp);
 612                 return (-1);
 613         }
 614 
 615         if (t.t_name != NULL) {
 616                 if (mdb_readstr(name, sizeof (name), (uintptr_t)t.t_name) == -1)
 617                         mdb_warn("error reading thread name");
 618 
 619                 /*
 620                  * Just to be safe -- if mdb_readstr() succeeds, it always NUL
 621                  * terminates the output, but is unclear what it does on
 622                  * failure.  In that case we attempt to show any partial content
 623                  * w/ the warning in case it's useful, but explicitly
 624                  * NUL-terminate to be safe.
 625                  */
 626                 buf[bufsize - 1] = '\0';
 627         }
 628 
 629         if (name[0] != '\0') {
 630                 if (include_comm) {
 631                         (void) mdb_snprintf(buf, bufsize, "%s/%u [%s]",
 632                             p.p_user.u_comm, t.t_tid, name);
 633                 } else {
 634                         (void) mdb_snprintf(buf, bufsize, "%u [%s]",
 635                             t.t_tid, name);
 636                 }
 637         } else {
 638                 if (include_comm) {
 639                         (void) mdb_snprintf(buf, bufsize, "%s/%u",
 640                             p.p_user.u_comm, t.t_tid);
 641                 } else {
 642                         (void) mdb_snprintf(buf, bufsize, "%u", t.t_tid);
 643                 }
 644         }
 645 
 646         return (buf[0] == '\0' ? -1 : 0);
 647 }
 648 
 649 /*
 650  * List a combination of kthread_t and proc_t. Add stack traces in verbose mode.
 651  */
 652 int
 653 threadlist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 654 {
 655         int i;
 656         uint_t count =  0;
 657         uint_t verbose = FALSE;
 658         uint_t notaskq = FALSE;
 659         kthread_t t;
 660         char cmd[80];
 661         mdb_arg_t cmdarg;
 662 
 663         if (!(flags & DCMD_ADDRSPEC)) {
 664                 if (mdb_walk_dcmd("thread", "threadlist", argc, argv) == -1) {
 665                         mdb_warn("can't walk threads");
 666                         return (DCMD_ERR);
 667                 }
 668                 return (DCMD_OK);
 669         }
 670 
 671         i = mdb_getopts(argc, argv,
 672             't', MDB_OPT_SETBITS, TRUE, &notaskq,
 673             'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL);
 674 
 675         if (i != argc) {
 676                 if (i != argc - 1 || !verbose)
 677                         return (DCMD_USAGE);
 678 
 679                 if (argv[i].a_type == MDB_TYPE_IMMEDIATE)
 680                         count = (uint_t)argv[i].a_un.a_val;
 681                 else
 682                         count = (uint_t)mdb_strtoull(argv[i].a_un.a_str);
 683         }
 684 
 685         if (DCMD_HDRSPEC(flags)) {
 686                 if (verbose)
 687                         mdb_printf("%<u>%?s %?s %?s %3s %3s %?s%</u>\n",
 688                             "ADDR", "PROC", "LWP", "CLS", "PRI", "WCHAN");
 689                 else
 690                         mdb_printf("%<u>%?s %?s %?s %s/%s%</u>\n",
 691                             "ADDR", "PROC", "LWP", "CMD", "LWPID");
 692         }
 693 
 694         if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {
 695                 mdb_warn("failed to read kthread_t at %p", addr);
 696                 return (DCMD_ERR);
 697         }
 698 
 699         if (notaskq && t.t_taskq != NULL)
 700                 return (DCMD_OK);
 701 
 702         if (t.t_state == TS_FREE)
 703                 return (DCMD_OK);
 704 
 705         if (!verbose) {
 706                 char desc[128];
 707 
 708                 if (thread_getdesc(addr, B_TRUE, desc, sizeof (desc)) == -1)
 709                         return (DCMD_ERR);
 710 
 711                 mdb_printf("%0?p %?p %?p %s\n", addr, t.t_procp, t.t_lwp, desc);
 712                 return (DCMD_OK);
 713         }
 714 
 715         mdb_printf("%0?p %?p %?p %3u %3d %?p\n",
 716             addr, t.t_procp, t.t_lwp, t.t_cid, t.t_pri, t.t_wchan);
 717 
 718         mdb_inc_indent(2);
 719 
 720         mdb_printf("PC: %a\n", t.t_pc);
 721 
 722         mdb_snprintf(cmd, sizeof (cmd), "<.$c%d", count);
 723         cmdarg.a_type = MDB_TYPE_STRING;
 724         cmdarg.a_un.a_str = cmd;
 725 
 726         (void) mdb_call_dcmd("findstack", addr, flags, 1, &cmdarg);
 727 
 728         mdb_dec_indent(2);
 729 
 730         mdb_printf("\n");
 731 
 732         return (DCMD_OK);
 733 }
 734 
 735 void
 736 threadlist_help(void)
 737 {
 738         mdb_printf(
 739             "   -v         print verbose output including C stack trace\n"
 740             "   -t         skip threads belonging to a taskq\n"
 741             "   count      print no more than count arguments (default 0)\n");
 742 }
 743 
 744 static size_t
 745 stk_compute_percent(caddr_t t_stk, caddr_t t_stkbase, caddr_t sp)
 746 {
 747         size_t percent;
 748         size_t s;
 749 
 750         if (t_stk > t_stkbase) {
 751                 /* stack grows down */
 752                 if (sp > t_stk) {
 753                         return (0);
 754                 }
 755                 if (sp < t_stkbase) {
 756                         return (100);
 757                 }
 758                 percent = t_stk - sp + 1;
 759                 s = t_stk - t_stkbase + 1;
 760         } else {
 761                 /* stack grows up */
 762                 if (sp < t_stk) {
 763                         return (0);
 764                 }
 765                 if (sp > t_stkbase) {
 766                         return (100);
 767                 }
 768                 percent = sp - t_stk + 1;
 769                 s = t_stkbase - t_stk + 1;
 770         }
 771         percent = ((100 * percent) / s) + 1;
 772         if (percent > 100) {
 773                 percent = 100;
 774         }
 775         return (percent);
 776 }
 777 
 778 /*
 779  * Display kthread stack infos.
 780  */
 781 int
 782 stackinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 783 {
 784         kthread_t t;
 785         uint64_t *ptr;  /* pattern pointer */
 786         caddr_t start;  /* kernel stack start */
 787         caddr_t end;    /* kernel stack end */
 788         caddr_t ustack; /* userland copy of kernel stack */
 789         size_t usize;   /* userland copy of kernel stack size */
 790         caddr_t ustart; /* userland copy of kernel stack, aligned start */
 791         caddr_t uend;   /* userland copy of kernel stack, aligned end */
 792         size_t percent = 0;
 793         uint_t all = FALSE; /* don't show TS_FREE kthread by default */
 794         uint_t history = FALSE;
 795         int i = 0;
 796         unsigned int ukmem_stackinfo;
 797         uintptr_t allthreads;
 798         char tdesc[128] = "";
 799 
 800         /* handle options */
 801         if (mdb_getopts(argc, argv,
 802             'a', MDB_OPT_SETBITS, TRUE, &all,
 803             'h', MDB_OPT_SETBITS, TRUE, &history, NULL) != argc) {
 804                 return (DCMD_USAGE);
 805         }
 806 
 807         /* walk all kthread if needed */
 808         if ((history == FALSE) && !(flags & DCMD_ADDRSPEC)) {
 809                 if (mdb_walk_dcmd("thread", "stackinfo", argc, argv) == -1) {
 810                         mdb_warn("can't walk threads");
 811                         return (DCMD_ERR);
 812                 }
 813                 return (DCMD_OK);
 814         }
 815 
 816         /* read 'kmem_stackinfo' */
 817         if (mdb_readsym(&ukmem_stackinfo, sizeof (ukmem_stackinfo),
 818             "kmem_stackinfo") == -1) {
 819                 mdb_warn("failed to read 'kmem_stackinfo'\n");
 820                 ukmem_stackinfo = 0;
 821         }
 822 
 823         /* read 'allthreads' */
 824         if (mdb_readsym(&allthreads, sizeof (kthread_t *),
 825             "allthreads") == -1) {
 826                 mdb_warn("failed to read 'allthreads'\n");
 827                 allthreads = NULL;
 828         }
 829 
 830         if (history == TRUE) {
 831                 kmem_stkinfo_t *log;
 832                 uintptr_t kaddr;
 833 
 834                 mdb_printf("Dead kthreads stack usage history:\n");
 835                 if (ukmem_stackinfo == 0) {
 836                         mdb_printf("Tunable kmem_stackinfo is unset, history ");
 837                         mdb_printf("feature is off.\nUse ::help stackinfo ");
 838                         mdb_printf("for more details.\n");
 839                         return (DCMD_OK);
 840                 }
 841 
 842                 mdb_printf("%<u>%?s%</u>", "THREAD");
 843                 mdb_printf(" %<u>%?s%</u>", "STACK");
 844                 mdb_printf("%<u>%s%</u>", "   SIZE  MAX LWP");
 845                 mdb_printf("\n");
 846                 usize = KMEM_STKINFO_LOG_SIZE * sizeof (kmem_stkinfo_t);
 847                 log = (kmem_stkinfo_t *)mdb_alloc(usize, UM_SLEEP);
 848                 if (mdb_readsym(&kaddr, sizeof (kaddr),
 849                     "kmem_stkinfo_log") == -1) {
 850                         mdb_free((void *)log, usize);
 851                         mdb_warn("failed to read 'kmem_stkinfo_log'\n");
 852                         return (DCMD_ERR);
 853                 }
 854                 if (kaddr == NULL) {
 855                         mdb_free((void *)log, usize);
 856                         return (DCMD_OK);
 857                 }
 858                 if (mdb_vread(log, usize, kaddr) == -1) {
 859                         mdb_free((void *)log, usize);
 860                         mdb_warn("failed to read %p\n", kaddr);
 861                         return (DCMD_ERR);
 862                 }
 863                 for (i = 0; i < KMEM_STKINFO_LOG_SIZE; i++) {
 864                         if (log[i].kthread == NULL) {
 865                                 continue;
 866                         }
 867 
 868                         (void) thread_getdesc((uintptr_t)log[i].kthread,
 869                             B_TRUE, tdesc, sizeof (tdesc));
 870 
 871                         mdb_printf("%0?p %0?p %6x %3d%% %s\n",
 872                             log[i].kthread,
 873                             log[i].start,
 874                             (uint_t)log[i].stksz,
 875                             (int)log[i].percent, tdesc);
 876                 }
 877                 mdb_free((void *)log, usize);
 878                 return (DCMD_OK);
 879         }
 880 
 881         /* display header */
 882         if (DCMD_HDRSPEC(flags)) {
 883                 if (ukmem_stackinfo == 0) {
 884                         mdb_printf("Tunable kmem_stackinfo is unset, ");
 885                         mdb_printf("MAX value is not available.\n");
 886                         mdb_printf("Use ::help stackinfo for more details.\n");
 887                 }
 888                 mdb_printf("%<u>%?s%</u>", "THREAD");
 889                 mdb_printf(" %<u>%?s%</u>", "STACK");
 890                 mdb_printf("%<u>%s%</u>", "   SIZE  CUR  MAX LWP");
 891                 mdb_printf("\n");
 892         }
 893 
 894         /* read kthread */
 895         if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {
 896                 mdb_warn("can't read kthread_t at %#lx\n", addr);
 897                 return (DCMD_ERR);
 898         }
 899 
 900         if (t.t_state == TS_FREE && all == FALSE) {
 901                 return (DCMD_OK);
 902         }
 903 
 904         /*
 905          * Stack grows up or down, see thread_create(),
 906          * compute stack memory aera start and end (start < end).
 907          */
 908         if (t.t_stk > t.t_stkbase) {
 909                 /* stack grows down */
 910                 start = t.t_stkbase;
 911                 end = t.t_stk;
 912         } else {
 913                 /* stack grows up */
 914                 start = t.t_stk;
 915                 end = t.t_stkbase;
 916         }
 917 
 918         /* display stack info */
 919         mdb_printf("%0?p %0?p", addr, start);
 920 
 921         /* (end - start), kernel stack size as found in kthread_t */
 922         if ((end <= start) || ((end - start) > (1024 * 1024))) {
 923                 /* negative or stack size > 1 meg, assume bogus */
 924                 mdb_warn(" t_stk/t_stkbase problem\n");
 925                 return (DCMD_ERR);
 926         }
 927 
 928         /* display stack size */
 929         mdb_printf(" %6x", end - start);
 930 
 931         /* display current stack usage */
 932         percent = stk_compute_percent(t.t_stk, t.t_stkbase,
 933             (caddr_t)t.t_sp + STACK_BIAS);
 934 
 935         mdb_printf(" %3d%%", percent);
 936         percent = 0;
 937 
 938         (void) thread_getdesc(addr, B_TRUE, tdesc, sizeof (tdesc));
 939 
 940         if (ukmem_stackinfo == 0) {
 941                 mdb_printf("  n/a %s\n", tdesc);
 942                 return (DCMD_OK);
 943         }
 944 
 945         if ((((uintptr_t)start) & 0x7) != 0) {
 946                 start = (caddr_t)((((uintptr_t)start) & (~0x7)) + 8);
 947         }
 948         end = (caddr_t)(((uintptr_t)end) & (~0x7));
 949         /* size to scan in userland copy of kernel stack */
 950         usize = end - start; /* is a multiple of 8 bytes */
 951 
 952         /*
 953          * Stackinfo pattern size is 8 bytes. Ensure proper 8 bytes
 954          * alignement for ustart and uend, in boundaries.
 955          */
 956         ustart = ustack = (caddr_t)mdb_alloc(usize + 8, UM_SLEEP);
 957         if ((((uintptr_t)ustart) & 0x7) != 0) {
 958                 ustart = (caddr_t)((((uintptr_t)ustart) & (~0x7)) + 8);
 959         }
 960         uend = ustart + usize;
 961 
 962         /* read the kernel stack */
 963         if (mdb_vread(ustart, usize, (uintptr_t)start) != usize) {
 964                 mdb_free((void *)ustack, usize + 8);
 965                 mdb_printf("\n");
 966                 mdb_warn("couldn't read entire stack\n");
 967                 return (DCMD_ERR);
 968         }
 969 
 970         /* scan the stack */
 971         if (t.t_stk > t.t_stkbase) {
 972                 /* stack grows down */
 973 #if defined(__i386) || defined(__amd64)
 974                 /*
 975                  * 6 longs are pushed on stack, see thread_load(). Skip
 976                  * them, so if kthread has never run, percent is zero.
 977                  * 8 bytes alignement is preserved for a 32 bit kernel,
 978                  * 6 x 4 = 24, 24 is a multiple of 8.
 979                  */
 980                 uend -= (6 * sizeof (long));
 981 #endif
 982                 ptr = (uint64_t *)((void *)ustart);
 983                 while (ptr < (uint64_t *)((void *)uend)) {
 984                         if (*ptr != KMEM_STKINFO_PATTERN) {
 985                                 percent = stk_compute_percent(uend,
 986                                     ustart, (caddr_t)ptr);
 987                                 break;
 988                         }
 989                         ptr++;
 990                 }
 991         } else {
 992                 /* stack grows up */
 993                 ptr = (uint64_t *)((void *)uend);
 994                 ptr--;
 995                 while (ptr >= (uint64_t *)((void *)ustart)) {
 996                         if (*ptr != KMEM_STKINFO_PATTERN) {
 997                                 percent = stk_compute_percent(ustart,
 998                                     uend, (caddr_t)ptr);
 999                                 break;
1000                         }
1001                         ptr--;
1002                 }
1003         }
1004 
1005         /* thread 't0' stack is not created by thread_create() */
1006         if (addr == allthreads) {
1007                 percent = 0;
1008         }
1009         if (percent != 0) {
1010                 mdb_printf(" %3d%%", percent);
1011         } else {
1012                 mdb_printf("  n/a");
1013         }
1014 
1015         mdb_printf(" %s\n", tdesc);
1016 
1017         mdb_free((void *)ustack, usize + 8);
1018         return (DCMD_OK);
1019 }
1020 
1021 void
1022 stackinfo_help(void)
1023 {
1024         mdb_printf(
1025             "Shows kernel stacks real utilization, if /etc/system "
1026             "kmem_stackinfo tunable\n");
1027         mdb_printf(
1028             "(an unsigned integer) is non zero at kthread creation time. ");
1029         mdb_printf("For example:\n");
1030         mdb_printf(
1031             "          THREAD            STACK   SIZE  CUR  MAX LWP\n");
1032         mdb_printf(
1033             "ffffff014f5f2c20 ffffff0004153000   4f00   4%%  43%% init/1\n");
1034         mdb_printf(
1035             "The stack size utilization for this kthread is at 4%%"
1036             " of its maximum size,\n");
1037         mdb_printf(
1038             "but has already used up to 43%%, stack size is 4f00 bytes.\n");
1039         mdb_printf(
1040             "MAX value can be shown as n/a (not available):\n");
1041         mdb_printf(
1042             "  - for the very first kthread (sched/1)\n");
1043         mdb_printf(
1044             "  - kmem_stackinfo was zero at kthread creation time\n");
1045         mdb_printf(
1046             "  - kthread has not yet run\n");
1047         mdb_printf("\n");
1048         mdb_printf("Options:\n");
1049         mdb_printf(
1050             "-a shows also TS_FREE kthreads (interrupt kthreads)\n");
1051         mdb_printf(
1052             "-h shows history, dead kthreads that used their "
1053             "kernel stack the most\n");
1054         mdb_printf(
1055             "\nSee illumos Modular Debugger Guide for detailed usage.\n");
1056         mdb_flush();
1057 }