1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright (c) 2013, Josef 'Jeff' Sipek <jeffpc@josefsipek.net> 25 * Copyright 2018 Joyent, Inc. 26 * Copyright 2025 Oxide Computer Company 27 */ 28 29 #include <mdb/mdb_modapi.h> 30 #include <mdb/mdb_ctf.h> 31 32 #include <sys/types.h> 33 #include <sys/regset.h> 34 #include <sys/stack.h> 35 #include <sys/thread.h> 36 #include <sys/modctl.h> 37 #include <assert.h> 38 39 #include "findstack.h" 40 #include "thread.h" 41 #include "sobj.h" 42 43 /* 44 * Parts of this file are shared between targets, but this section is only 45 * used for KVM and KMDB. 46 */ 47 #ifdef _KERNEL 48 49 int findstack_debug_on = 0; 50 51 /* 52 * "sp" is a kernel VA. 53 */ 54 static int 55 print_stack(uintptr_t sp, uintptr_t pc, uintptr_t addr, 56 int argc, const mdb_arg_t *argv, int free_state) 57 { 58 boolean_t showargs = B_FALSE; 59 boolean_t types = B_FALSE; 60 boolean_t sizes = B_FALSE; 61 boolean_t addrs = B_FALSE; 62 int count, err; 63 char tdesc[128] = ""; 64 65 count = mdb_getopts(argc, argv, 66 'n', MDB_OPT_SETBITS, TRUE, &addrs, 67 's', MDB_OPT_SETBITS, TRUE, &sizes, 68 't', MDB_OPT_SETBITS, TRUE, &types, 69 'v', MDB_OPT_SETBITS, TRUE, &showargs, 70 NULL); 71 argc -= count; 72 argv += count; 73 74 if (argc > 1 || (argc == 1 && argv->a_type != MDB_TYPE_STRING)) 75 return (DCMD_USAGE); 76 77 (void) thread_getdesc(addr, B_TRUE, tdesc, sizeof (tdesc)); 78 79 mdb_printf("stack pointer for thread %p%s (%s): %p\n", 80 addr, (free_state ? " (TS_FREE)" : ""), tdesc, sp); 81 if (pc != 0) 82 mdb_printf("[ %0?lr %a() ]\n", sp, pc); 83 84 mdb_inc_indent(2); 85 mdb_set_dot(sp); 86 87 if (argc == 1) { 88 err = mdb_eval(argv->a_un.a_str); 89 } else { 90 (void) mdb_snprintf(tdesc, sizeof (tdesc), 91 "<.$C%s%s%s%s", 92 addrs ? " -n" : "", 93 sizes ? " -s" : "", 94 types ? " -t" : "", 95 showargs ? "" : " 0"); 96 err = mdb_eval(tdesc); 97 } 98 99 mdb_dec_indent(2); 100 101 return ((err == -1) ? DCMD_ABORT : DCMD_OK); 102 } 103 104 int 105 findstack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 106 { 107 findstack_info_t fsi; 108 int retval; 109 110 if (!(flags & DCMD_ADDRSPEC)) 111 return (DCMD_USAGE); 112 113 bzero(&fsi, sizeof (fsi)); 114 115 if ((retval = stacks_findstack(addr, &fsi, 1)) != DCMD_OK || 116 fsi.fsi_failed) 117 return (retval); 118 119 return (print_stack(fsi.fsi_sp, fsi.fsi_pc, addr, 120 argc, argv, fsi.fsi_tstate == TS_FREE)); 121 } 122 123 /*ARGSUSED*/ 124 int 125 findstack_debug(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *av) 126 { 127 findstack_debug_on ^= 1; 128 129 mdb_printf("findstack: debugging is now %s\n", 130 findstack_debug_on ? "on" : "off"); 131 132 return (DCMD_OK); 133 } 134 135 #endif /* _KERNEL */ 136 137 static void 138 uppercase(char *p) 139 { 140 for (; *p != '\0'; p++) { 141 if (*p >= 'a' && *p <= 'z') 142 *p += 'A' - 'a'; 143 } 144 } 145 146 static void 147 sobj_to_text(uintptr_t addr, char *out, size_t out_sz) 148 { 149 sobj_ops_to_text(addr, out, out_sz); 150 uppercase(out); 151 } 152 153 #define SOBJ_ALL 1 154 155 static int 156 text_to_sobj(const char *text, uintptr_t *out) 157 { 158 if (strcasecmp(text, "ALL") == 0) { 159 *out = SOBJ_ALL; 160 return (0); 161 } 162 163 return (sobj_text_to_ops(text, out)); 164 } 165 166 #define TSTATE_PANIC -2U 167 static int 168 text_to_tstate(const char *text, uint_t *out) 169 { 170 if (strcasecmp(text, "panic") == 0) 171 *out = TSTATE_PANIC; 172 else if (thread_text_to_state(text, out) != 0) { 173 mdb_warn("tstate \"%s\" not recognized\n", text); 174 return (-1); 175 } 176 return (0); 177 } 178 179 static void 180 tstate_to_text(uint_t tstate, uint_t paniced, char *out, size_t out_sz) 181 { 182 if (paniced) 183 mdb_snprintf(out, out_sz, "panic"); 184 else 185 thread_state_to_text(tstate, out, out_sz); 186 uppercase(out); 187 } 188 189 typedef struct stacks_entry { 190 struct stacks_entry *se_next; 191 struct stacks_entry *se_dup; /* dups of this stack */ 192 uintptr_t se_thread; 193 uintptr_t se_sp; 194 uintptr_t se_sobj_ops; 195 uint32_t se_tstate; 196 uint32_t se_count; /* # threads w/ this stack */ 197 uint8_t se_overflow; 198 uint8_t se_depth; 199 uint8_t se_failed; /* failure reason; FSI_FAIL_* */ 200 uint8_t se_panic; 201 uintptr_t se_stack[1]; 202 } stacks_entry_t; 203 #define STACKS_ENTRY_SIZE(x) OFFSETOF(stacks_entry_t, se_stack[(x)]) 204 205 #define STACKS_HSIZE 127 206 207 /* Maximum stack depth reported in stacks */ 208 #define STACKS_MAX_DEPTH 254 209 210 typedef struct stacks_info { 211 size_t si_count; /* total stacks_entry_ts (incl dups) */ 212 size_t si_entries; /* # entries in hash table */ 213 stacks_entry_t **si_hash; /* hash table */ 214 findstack_info_t si_fsi; /* transient callback state */ 215 } stacks_info_t; 216 217 /* global state cached between invocations */ 218 #define STACKS_STATE_CLEAN 0 219 #define STACKS_STATE_DIRTY 1 220 #define STACKS_STATE_DONE 2 221 static uint_t stacks_state = STACKS_STATE_CLEAN; 222 static stacks_entry_t **stacks_hash; 223 static stacks_entry_t **stacks_array; 224 static size_t stacks_array_size; 225 226 static size_t 227 stacks_hash_entry(stacks_entry_t *sep) 228 { 229 size_t depth = sep->se_depth; 230 uintptr_t *stack = sep->se_stack; 231 232 uint64_t total = depth; 233 234 while (depth > 0) { 235 total += *stack; 236 stack++; depth--; 237 } 238 239 return (total % STACKS_HSIZE); 240 } 241 242 /* 243 * This is used to both compare stacks for equality and to sort the final 244 * list of unique stacks. forsort specifies the latter behavior, which 245 * additionally: 246 * compares se_count, and 247 * sorts the stacks by text function name. 248 * 249 * The equality test is independent of se_count, and doesn't care about 250 * relative ordering, so we don't do the extra work of looking up symbols 251 * for the stack addresses. 252 */ 253 static int 254 stacks_entry_comp_impl(stacks_entry_t *l, stacks_entry_t *r, 255 uint_t forsort) 256 { 257 int idx; 258 259 int depth = MIN(l->se_depth, r->se_depth); 260 261 /* no matter what, panic stacks come last. */ 262 if (l->se_panic > r->se_panic) 263 return (1); 264 if (l->se_panic < r->se_panic) 265 return (-1); 266 267 if (forsort) { 268 /* put large counts earlier */ 269 if (l->se_count > r->se_count) 270 return (-1); 271 if (l->se_count < r->se_count) 272 return (1); 273 } 274 275 if (l->se_tstate > r->se_tstate) 276 return (1); 277 if (l->se_tstate < r->se_tstate) 278 return (-1); 279 280 if (l->se_failed > r->se_failed) 281 return (1); 282 if (l->se_failed < r->se_failed) 283 return (-1); 284 285 for (idx = 0; idx < depth; idx++) { 286 char lbuf[MDB_SYM_NAMLEN]; 287 char rbuf[MDB_SYM_NAMLEN]; 288 289 int rval; 290 uintptr_t laddr = l->se_stack[idx]; 291 uintptr_t raddr = r->se_stack[idx]; 292 293 if (laddr == raddr) 294 continue; 295 296 if (forsort && 297 mdb_lookup_by_addr(laddr, MDB_SYM_FUZZY, 298 lbuf, sizeof (lbuf), NULL) != -1 && 299 mdb_lookup_by_addr(raddr, MDB_SYM_FUZZY, 300 rbuf, sizeof (rbuf), NULL) != -1 && 301 (rval = strcmp(lbuf, rbuf)) != 0) 302 return (rval); 303 304 if (laddr > raddr) 305 return (1); 306 return (-1); 307 } 308 309 if (l->se_overflow > r->se_overflow) 310 return (-1); 311 if (l->se_overflow < r->se_overflow) 312 return (1); 313 314 if (l->se_depth > r->se_depth) 315 return (1); 316 if (l->se_depth < r->se_depth) 317 return (-1); 318 319 if (l->se_sobj_ops > r->se_sobj_ops) 320 return (1); 321 if (l->se_sobj_ops < r->se_sobj_ops) 322 return (-1); 323 324 return (0); 325 } 326 327 static int 328 stacks_entry_comp(const void *l_arg, const void *r_arg) 329 { 330 stacks_entry_t * const *lp = l_arg; 331 stacks_entry_t * const *rp = r_arg; 332 333 return (stacks_entry_comp_impl(*lp, *rp, 1)); 334 } 335 336 void 337 stacks_cleanup(int force) 338 { 339 int idx = 0; 340 stacks_entry_t *cur, *next; 341 342 if (stacks_state == STACKS_STATE_CLEAN) 343 return; 344 345 if (!force && stacks_state == STACKS_STATE_DONE) 346 return; 347 348 /* 349 * Until the array is sorted and stable, stacks_hash will be non-NULL. 350 * This way, we can get at all of the data, even if qsort() was 351 * interrupted while mucking with the array. 352 */ 353 if (stacks_hash != NULL) { 354 for (idx = 0; idx < STACKS_HSIZE; idx++) { 355 while ((cur = stacks_hash[idx]) != NULL) { 356 while ((next = cur->se_dup) != NULL) { 357 cur->se_dup = next->se_dup; 358 mdb_free(next, 359 STACKS_ENTRY_SIZE(next->se_depth)); 360 } 361 next = cur->se_next; 362 stacks_hash[idx] = next; 363 mdb_free(cur, STACKS_ENTRY_SIZE(cur->se_depth)); 364 } 365 } 366 if (stacks_array != NULL) 367 mdb_free(stacks_array, 368 stacks_array_size * sizeof (*stacks_array)); 369 370 mdb_free(stacks_hash, STACKS_HSIZE * sizeof (*stacks_hash)); 371 372 } else if (stacks_array != NULL) { 373 for (idx = 0; idx < stacks_array_size; idx++) { 374 if ((cur = stacks_array[idx]) != NULL) { 375 while ((next = cur->se_dup) != NULL) { 376 cur->se_dup = next->se_dup; 377 mdb_free(next, 378 STACKS_ENTRY_SIZE(next->se_depth)); 379 } 380 stacks_array[idx] = NULL; 381 mdb_free(cur, STACKS_ENTRY_SIZE(cur->se_depth)); 382 } 383 } 384 mdb_free(stacks_array, 385 stacks_array_size * sizeof (*stacks_array)); 386 } 387 388 stacks_findstack_cleanup(); 389 390 stacks_array_size = 0; 391 stacks_state = STACKS_STATE_CLEAN; 392 stacks_hash = NULL; 393 stacks_array = NULL; 394 } 395 396 /*ARGSUSED*/ 397 static int 398 stacks_thread_cb(uintptr_t addr, const void *ignored, void *cbarg) 399 { 400 stacks_info_t *sip = cbarg; 401 findstack_info_t *fsip = &sip->si_fsi; 402 403 stacks_entry_t **sepp, *nsep, *sep; 404 int idx; 405 size_t depth; 406 407 if (stacks_findstack(addr, fsip, 0) != DCMD_OK && 408 fsip->fsi_failed == FSI_FAIL_BADTHREAD) { 409 mdb_warn("couldn't read thread at %p\n", addr); 410 return (WALK_NEXT); 411 } 412 413 sip->si_count++; 414 415 depth = fsip->fsi_depth; 416 nsep = mdb_zalloc(STACKS_ENTRY_SIZE(depth), UM_SLEEP); 417 nsep->se_thread = addr; 418 nsep->se_sp = fsip->fsi_sp; 419 nsep->se_sobj_ops = fsip->fsi_sobj_ops; 420 nsep->se_tstate = fsip->fsi_tstate; 421 nsep->se_count = 1; 422 nsep->se_overflow = fsip->fsi_overflow; 423 nsep->se_depth = depth; 424 nsep->se_failed = fsip->fsi_failed; 425 nsep->se_panic = fsip->fsi_panic; 426 427 for (idx = 0; idx < depth; idx++) 428 nsep->se_stack[idx] = fsip->fsi_stack[idx]; 429 430 for (sepp = &sip->si_hash[stacks_hash_entry(nsep)]; 431 (sep = *sepp) != NULL; 432 sepp = &sep->se_next) { 433 434 if (stacks_entry_comp_impl(sep, nsep, 0) != 0) 435 continue; 436 437 nsep->se_dup = sep->se_dup; 438 sep->se_dup = nsep; 439 sep->se_count++; 440 return (WALK_NEXT); 441 } 442 443 nsep->se_next = NULL; 444 *sepp = nsep; 445 sip->si_entries++; 446 447 return (WALK_NEXT); 448 } 449 450 static int 451 stacks_run_tlist(mdb_pipe_t *tlist, stacks_info_t *si) 452 { 453 size_t idx; 454 size_t found = 0; 455 int ret; 456 457 for (idx = 0; idx < tlist->pipe_len; idx++) { 458 uintptr_t addr = tlist->pipe_data[idx]; 459 460 found++; 461 462 ret = stacks_thread_cb(addr, NULL, si); 463 if (ret == WALK_DONE) 464 break; 465 if (ret != WALK_NEXT) 466 return (-1); 467 } 468 469 if (found) 470 return (0); 471 return (-1); 472 } 473 474 static int 475 stacks_run(int verbose, mdb_pipe_t *tlist) 476 { 477 stacks_info_t si; 478 findstack_info_t *fsip = &si.si_fsi; 479 size_t idx; 480 stacks_entry_t **cur; 481 482 bzero(&si, sizeof (si)); 483 484 stacks_state = STACKS_STATE_DIRTY; 485 486 stacks_hash = si.si_hash = 487 mdb_zalloc(STACKS_HSIZE * sizeof (*si.si_hash), UM_SLEEP); 488 si.si_entries = 0; 489 si.si_count = 0; 490 491 fsip->fsi_max_depth = STACKS_MAX_DEPTH; 492 fsip->fsi_stack = 493 mdb_alloc(fsip->fsi_max_depth * sizeof (*fsip->fsi_stack), 494 UM_SLEEP | UM_GC); 495 496 if (verbose) 497 mdb_warn("stacks: processing kernel threads\n"); 498 499 if (tlist != NULL) { 500 if (stacks_run_tlist(tlist, &si)) 501 return (DCMD_ERR); 502 } else { 503 if (mdb_walk("thread", stacks_thread_cb, &si) != 0) { 504 mdb_warn("cannot walk \"thread\""); 505 return (DCMD_ERR); 506 } 507 } 508 509 if (verbose) 510 mdb_warn("stacks: %d unique stacks / %d threads\n", 511 si.si_entries, si.si_count); 512 513 stacks_array_size = si.si_entries; 514 stacks_array = 515 mdb_zalloc(si.si_entries * sizeof (*stacks_array), UM_SLEEP); 516 cur = stacks_array; 517 for (idx = 0; idx < STACKS_HSIZE; idx++) { 518 stacks_entry_t *sep; 519 for (sep = si.si_hash[idx]; sep != NULL; sep = sep->se_next) 520 *(cur++) = sep; 521 } 522 523 if (cur != stacks_array + si.si_entries) { 524 mdb_warn("stacks: miscounted array size (%d != size: %d)\n", 525 (cur - stacks_array), stacks_array_size); 526 return (DCMD_ERR); 527 } 528 qsort(stacks_array, si.si_entries, sizeof (*stacks_array), 529 stacks_entry_comp); 530 531 /* Now that we're done, free the hash table */ 532 stacks_hash = NULL; 533 mdb_free(si.si_hash, STACKS_HSIZE * sizeof (*si.si_hash)); 534 535 if (tlist == NULL) 536 stacks_state = STACKS_STATE_DONE; 537 538 if (verbose) 539 mdb_warn("stacks: done\n"); 540 541 return (DCMD_OK); 542 } 543 544 static int 545 stacks_has_caller(stacks_entry_t *sep, uintptr_t addr) 546 { 547 uintptr_t laddr = addr; 548 uintptr_t haddr = addr + 1; 549 int idx; 550 char c[MDB_SYM_NAMLEN]; 551 GElf_Sym sym; 552 553 if (mdb_lookup_by_addr(addr, MDB_SYM_FUZZY, 554 c, sizeof (c), &sym) != -1 && 555 addr == (uintptr_t)sym.st_value) { 556 laddr = (uintptr_t)sym.st_value; 557 haddr = (uintptr_t)sym.st_value + sym.st_size; 558 } 559 560 for (idx = 0; idx < sep->se_depth; idx++) 561 if (sep->se_stack[idx] >= laddr && sep->se_stack[idx] < haddr) 562 return (1); 563 564 return (0); 565 } 566 567 static int 568 stacks_has_module(stacks_entry_t *sep, stacks_module_t *mp) 569 { 570 int idx; 571 572 for (idx = 0; idx < sep->se_depth; idx++) { 573 if (sep->se_stack[idx] >= mp->sm_text && 574 sep->se_stack[idx] < mp->sm_text + mp->sm_size) 575 return (1); 576 } 577 578 return (0); 579 } 580 581 static int 582 stacks_module_find(const char *name, stacks_module_t *mp) 583 { 584 (void) strncpy(mp->sm_name, name, sizeof (mp->sm_name)); 585 586 if (stacks_module(mp) != 0) 587 return (-1); 588 589 if (mp->sm_size == 0) { 590 mdb_warn("stacks: module \"%s\" is unknown\n", name); 591 return (-1); 592 } 593 594 return (0); 595 } 596 597 static int 598 uintptrcomp(const void *lp, const void *rp) 599 { 600 uintptr_t lhs = *(const uintptr_t *)lp; 601 uintptr_t rhs = *(const uintptr_t *)rp; 602 if (lhs > rhs) 603 return (1); 604 if (lhs < rhs) 605 return (-1); 606 return (0); 607 } 608 609 /*ARGSUSED*/ 610 int 611 stacks(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 612 { 613 size_t idx; 614 615 char *seen = NULL; 616 617 const char *caller_str = NULL; 618 const char *excl_caller_str = NULL; 619 uintptr_t caller = 0, excl_caller = 0; 620 const char *module_str = NULL; 621 const char *excl_module_str = NULL; 622 stacks_module_t module, excl_module; 623 const char *sobj = NULL; 624 const char *excl_sobj = NULL; 625 uintptr_t sobj_ops = 0, excl_sobj_ops = 0; 626 const char *tstate_str = NULL; 627 const char *excl_tstate_str = NULL; 628 uint_t tstate = -1U; 629 uint_t excl_tstate = -1U; 630 uint_t printed = 0; 631 632 uint_t all = 0; 633 uint_t force = 0; 634 uint_t interesting = 0; 635 uint_t verbose = 0; 636 637 /* 638 * We have a slight behavior difference between having piped 639 * input and 'addr::stacks'. Without a pipe, we assume the 640 * thread pointer given is a representative thread, and so 641 * we include all similar threads in the system in our output. 642 * 643 * With a pipe, we filter down to just the threads in our 644 * input. 645 */ 646 uint_t addrspec = (flags & DCMD_ADDRSPEC); 647 uint_t only_matching = addrspec && (flags & DCMD_PIPE); 648 649 mdb_pipe_t p; 650 651 bzero(&module, sizeof (module)); 652 bzero(&excl_module, sizeof (excl_module)); 653 654 if (mdb_getopts(argc, argv, 655 'a', MDB_OPT_SETBITS, TRUE, &all, 656 'f', MDB_OPT_SETBITS, TRUE, &force, 657 'i', MDB_OPT_SETBITS, TRUE, &interesting, 658 'v', MDB_OPT_SETBITS, TRUE, &verbose, 659 'c', MDB_OPT_STR, &caller_str, 660 'C', MDB_OPT_STR, &excl_caller_str, 661 'm', MDB_OPT_STR, &module_str, 662 'M', MDB_OPT_STR, &excl_module_str, 663 's', MDB_OPT_STR, &sobj, 664 'S', MDB_OPT_STR, &excl_sobj, 665 't', MDB_OPT_STR, &tstate_str, 666 'T', MDB_OPT_STR, &excl_tstate_str, 667 NULL) != argc) 668 return (DCMD_USAGE); 669 670 if (interesting) { 671 if (sobj != NULL || excl_sobj != NULL || 672 tstate_str != NULL || excl_tstate_str != NULL) { 673 mdb_warn( 674 "stacks: -i is incompatible with -[sStT]\n"); 675 return (DCMD_USAGE); 676 } 677 excl_sobj = "CV"; 678 excl_tstate_str = "FREE"; 679 } 680 681 if (caller_str != NULL) { 682 mdb_set_dot(0); 683 if (mdb_eval(caller_str) != 0) { 684 mdb_warn("stacks: evaluation of \"%s\" failed", 685 caller_str); 686 return (DCMD_ABORT); 687 } 688 caller = mdb_get_dot(); 689 } 690 691 if (excl_caller_str != NULL) { 692 mdb_set_dot(0); 693 if (mdb_eval(excl_caller_str) != 0) { 694 mdb_warn("stacks: evaluation of \"%s\" failed", 695 excl_caller_str); 696 return (DCMD_ABORT); 697 } 698 excl_caller = mdb_get_dot(); 699 } 700 mdb_set_dot(addr); 701 702 if (module_str != NULL && stacks_module_find(module_str, &module) != 0) 703 return (DCMD_ABORT); 704 705 if (excl_module_str != NULL && 706 stacks_module_find(excl_module_str, &excl_module) != 0) 707 return (DCMD_ABORT); 708 709 if (sobj != NULL && text_to_sobj(sobj, &sobj_ops) != 0) 710 return (DCMD_USAGE); 711 712 if (excl_sobj != NULL && text_to_sobj(excl_sobj, &excl_sobj_ops) != 0) 713 return (DCMD_USAGE); 714 715 if (sobj_ops != 0 && excl_sobj_ops != 0) { 716 mdb_warn("stacks: only one of -s and -S can be specified\n"); 717 return (DCMD_USAGE); 718 } 719 720 if (tstate_str != NULL && text_to_tstate(tstate_str, &tstate) != 0) 721 return (DCMD_USAGE); 722 723 if (excl_tstate_str != NULL && 724 text_to_tstate(excl_tstate_str, &excl_tstate) != 0) 725 return (DCMD_USAGE); 726 727 if (tstate != -1U && excl_tstate != -1U) { 728 mdb_warn("stacks: only one of -t and -T can be specified\n"); 729 return (DCMD_USAGE); 730 } 731 732 /* 733 * If there's an address specified, we're going to further filter 734 * to only entries which have an address in the input. To reduce 735 * overhead (and make the sorted output come out right), we 736 * use mdb_get_pipe() to grab the entire pipeline of input, then 737 * use qsort() and bsearch() to speed up the search. 738 */ 739 if (addrspec) { 740 mdb_get_pipe(&p); 741 if (p.pipe_data == NULL || p.pipe_len == 0) { 742 p.pipe_data = &addr; 743 p.pipe_len = 1; 744 } 745 qsort(p.pipe_data, p.pipe_len, sizeof (uintptr_t), 746 uintptrcomp); 747 748 /* remove any duplicates in the data */ 749 idx = 0; 750 while (idx < p.pipe_len - 1) { 751 uintptr_t *data = &p.pipe_data[idx]; 752 size_t len = p.pipe_len - idx; 753 754 if (data[0] == data[1]) { 755 memmove(data, data + 1, 756 (len - 1) * sizeof (*data)); 757 p.pipe_len--; 758 continue; /* repeat without incrementing idx */ 759 } 760 idx++; 761 } 762 763 seen = mdb_zalloc(p.pipe_len, UM_SLEEP | UM_GC); 764 } 765 766 /* 767 * Force a cleanup if we're connected to a live system. Never 768 * do a cleanup after the first invocation around the loop. 769 */ 770 force |= (mdb_get_state() == MDB_STATE_RUNNING); 771 if (force && (flags & (DCMD_LOOPFIRST|DCMD_LOOP)) == DCMD_LOOP) 772 force = 0; 773 774 stacks_cleanup(force); 775 776 if (stacks_state == STACKS_STATE_CLEAN) { 777 int res = stacks_run(verbose, addrspec ? &p : NULL); 778 if (res != DCMD_OK) 779 return (res); 780 } 781 782 for (idx = 0; idx < stacks_array_size; idx++) { 783 stacks_entry_t *sep = stacks_array[idx]; 784 stacks_entry_t *cur = sep; 785 int frame; 786 size_t count = sep->se_count; 787 788 if (addrspec) { 789 stacks_entry_t *head = NULL, *tail = NULL, *sp; 790 size_t foundcount = 0; 791 /* 792 * We use the now-unused hash chain field se_next to 793 * link together the dups which match our list. 794 */ 795 for (sp = sep; sp != NULL; sp = sp->se_dup) { 796 uintptr_t *entry = bsearch(&sp->se_thread, 797 p.pipe_data, p.pipe_len, sizeof (uintptr_t), 798 uintptrcomp); 799 if (entry != NULL) { 800 foundcount++; 801 seen[entry - p.pipe_data]++; 802 if (head == NULL) 803 head = sp; 804 else 805 tail->se_next = sp; 806 tail = sp; 807 sp->se_next = NULL; 808 } 809 } 810 if (head == NULL) 811 continue; /* no match, skip entry */ 812 813 if (only_matching) { 814 cur = sep = head; 815 count = foundcount; 816 } 817 } 818 819 if (caller != 0 && !stacks_has_caller(sep, caller)) 820 continue; 821 822 if (excl_caller != 0 && stacks_has_caller(sep, excl_caller)) 823 continue; 824 825 if (module.sm_size != 0 && !stacks_has_module(sep, &module)) 826 continue; 827 828 if (excl_module.sm_size != 0 && 829 stacks_has_module(sep, &excl_module)) 830 continue; 831 832 if (tstate != -1U) { 833 if (tstate == TSTATE_PANIC) { 834 if (!sep->se_panic) 835 continue; 836 } else if (sep->se_panic || sep->se_tstate != tstate) 837 continue; 838 } 839 if (excl_tstate != -1U) { 840 if (excl_tstate == TSTATE_PANIC) { 841 if (sep->se_panic) 842 continue; 843 } else if (!sep->se_panic && 844 sep->se_tstate == excl_tstate) 845 continue; 846 } 847 848 if (sobj_ops == SOBJ_ALL) { 849 if (sep->se_sobj_ops == 0) 850 continue; 851 } else if (sobj_ops != 0) { 852 if (sobj_ops != sep->se_sobj_ops) 853 continue; 854 } 855 856 if (!(interesting && sep->se_panic)) { 857 if (excl_sobj_ops == SOBJ_ALL) { 858 if (sep->se_sobj_ops != 0) 859 continue; 860 } else if (excl_sobj_ops != 0) { 861 if (excl_sobj_ops == sep->se_sobj_ops) 862 continue; 863 } 864 } 865 866 if (flags & DCMD_PIPE_OUT) { 867 while (sep != NULL) { 868 mdb_printf("%lr\n", sep->se_thread); 869 sep = only_matching ? 870 sep->se_next : sep->se_dup; 871 } 872 continue; 873 } 874 875 if (all || !printed) { 876 mdb_printf("%<u>%-?s %-8s %-?s %8s%</u>\n", 877 "THREAD", "STATE", "SOBJ", "COUNT"); 878 printed = 1; 879 } 880 881 do { 882 char state[20]; 883 char sobj[100]; 884 885 tstate_to_text(cur->se_tstate, cur->se_panic, 886 state, sizeof (state)); 887 sobj_to_text(cur->se_sobj_ops, 888 sobj, sizeof (sobj)); 889 890 if (cur == sep) 891 mdb_printf("%-?p %-8s %-?s %8d\n", 892 cur->se_thread, state, sobj, count); 893 else 894 mdb_printf("%-?p %-8s %-?s %8s\n", 895 cur->se_thread, state, sobj, "-"); 896 897 cur = only_matching ? cur->se_next : cur->se_dup; 898 } while (all && cur != NULL); 899 900 if (sep->se_failed != 0) { 901 char *reason; 902 switch (sep->se_failed) { 903 case FSI_FAIL_NOTINMEMORY: 904 reason = "thread not in memory"; 905 break; 906 case FSI_FAIL_THREADCORRUPT: 907 reason = "thread structure stack info corrupt"; 908 break; 909 case FSI_FAIL_STACKNOTFOUND: 910 reason = "no consistent stack found"; 911 break; 912 default: 913 reason = "unknown failure"; 914 break; 915 } 916 mdb_printf("%?s <%s>\n", "", reason); 917 } 918 919 for (frame = 0; frame < sep->se_depth; frame++) 920 mdb_printf("%?s %a\n", "", sep->se_stack[frame]); 921 if (sep->se_overflow) 922 mdb_printf("%?s ... truncated ...\n", ""); 923 mdb_printf("\n"); 924 } 925 926 if (flags & DCMD_ADDRSPEC) { 927 for (idx = 0; idx < p.pipe_len; idx++) 928 if (seen[idx] == 0) 929 mdb_warn("stacks: %p not in thread list\n", 930 p.pipe_data[idx]); 931 } 932 return (DCMD_OK); 933 } 934