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