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