8158 Want named threads API
[unleashed.git] / usr / src / cmd / mdb / common / modules / genunix / findstack.c
blobfc8a4f874b88854562c76bc81c74b8665cdfbe35
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
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.
28 #include <mdb/mdb_modapi.h>
29 #include <mdb/mdb_ctf.h>
31 #include <sys/types.h>
32 #include <sys/regset.h>
33 #include <sys/stack.h>
34 #include <sys/thread.h>
35 #include <sys/modctl.h>
36 #include <assert.h>
38 #include "findstack.h"
39 #include "thread.h"
40 #include "sobj.h"
43 * Parts of this file are shared between targets, but this section is only
44 * used for KVM and KMDB.
46 #ifdef _KERNEL
48 int findstack_debug_on = 0;
51 * "sp" is a kernel VA.
53 static int
54 print_stack(uintptr_t sp, uintptr_t pc, uintptr_t addr,
55 int argc, const mdb_arg_t *argv, int free_state)
57 int showargs = 0, count, err;
58 char tdesc[128] = "";
60 count = mdb_getopts(argc, argv,
61 'v', MDB_OPT_SETBITS, TRUE, &showargs, NULL);
62 argc -= count;
63 argv += count;
65 if (argc > 1 || (argc == 1 && argv->a_type != MDB_TYPE_STRING))
66 return (DCMD_USAGE);
68 (void) thread_getdesc(addr, B_TRUE, tdesc, sizeof (tdesc));
70 mdb_printf("stack pointer for thread %p%s (%s): %p\n",
71 addr, (free_state ? " (TS_FREE)" : ""), tdesc, sp);
72 if (pc != 0)
73 mdb_printf("[ %0?lr %a() ]\n", sp, pc);
75 mdb_inc_indent(2);
76 mdb_set_dot(sp);
78 if (argc == 1)
79 err = mdb_eval(argv->a_un.a_str);
80 else if (showargs)
81 err = mdb_eval("<.$C");
82 else
83 err = mdb_eval("<.$C0");
85 mdb_dec_indent(2);
87 return ((err == -1) ? DCMD_ABORT : DCMD_OK);
90 int
91 findstack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
93 findstack_info_t fsi;
94 int retval;
96 if (!(flags & DCMD_ADDRSPEC))
97 return (DCMD_USAGE);
99 bzero(&fsi, sizeof (fsi));
101 if ((retval = stacks_findstack(addr, &fsi, 1)) != DCMD_OK ||
102 fsi.fsi_failed)
103 return (retval);
105 return (print_stack(fsi.fsi_sp, fsi.fsi_pc, addr,
106 argc, argv, fsi.fsi_tstate == TS_FREE));
109 /*ARGSUSED*/
111 findstack_debug(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *av)
113 findstack_debug_on ^= 1;
115 mdb_printf("findstack: debugging is now %s\n",
116 findstack_debug_on ? "on" : "off");
118 return (DCMD_OK);
121 #endif /* _KERNEL */
123 static void
124 uppercase(char *p)
126 for (; *p != '\0'; p++) {
127 if (*p >= 'a' && *p <= 'z')
128 *p += 'A' - 'a';
132 static void
133 sobj_to_text(uintptr_t addr, char *out, size_t out_sz)
135 sobj_ops_to_text(addr, out, out_sz);
136 uppercase(out);
139 #define SOBJ_ALL 1
141 static int
142 text_to_sobj(const char *text, uintptr_t *out)
144 if (strcasecmp(text, "ALL") == 0) {
145 *out = SOBJ_ALL;
146 return (0);
149 return (sobj_text_to_ops(text, out));
152 #define TSTATE_PANIC -2U
153 static int
154 text_to_tstate(const char *text, uint_t *out)
156 if (strcasecmp(text, "panic") == 0)
157 *out = TSTATE_PANIC;
158 else if (thread_text_to_state(text, out) != 0) {
159 mdb_warn("tstate \"%s\" not recognized\n", text);
160 return (-1);
162 return (0);
165 static void
166 tstate_to_text(uint_t tstate, uint_t paniced, char *out, size_t out_sz)
168 if (paniced)
169 mdb_snprintf(out, out_sz, "panic");
170 else
171 thread_state_to_text(tstate, out, out_sz);
172 uppercase(out);
175 typedef struct stacks_entry {
176 struct stacks_entry *se_next;
177 struct stacks_entry *se_dup; /* dups of this stack */
178 uintptr_t se_thread;
179 uintptr_t se_sp;
180 uintptr_t se_sobj_ops;
181 uint32_t se_tstate;
182 uint32_t se_count; /* # threads w/ this stack */
183 uint8_t se_overflow;
184 uint8_t se_depth;
185 uint8_t se_failed; /* failure reason; FSI_FAIL_* */
186 uint8_t se_panic;
187 uintptr_t se_stack[1];
188 } stacks_entry_t;
189 #define STACKS_ENTRY_SIZE(x) OFFSETOF(stacks_entry_t, se_stack[(x)])
191 #define STACKS_HSIZE 127
193 /* Maximum stack depth reported in stacks */
194 #define STACKS_MAX_DEPTH 254
196 typedef struct stacks_info {
197 size_t si_count; /* total stacks_entry_ts (incl dups) */
198 size_t si_entries; /* # entries in hash table */
199 stacks_entry_t **si_hash; /* hash table */
200 findstack_info_t si_fsi; /* transient callback state */
201 } stacks_info_t;
203 /* global state cached between invocations */
204 #define STACKS_STATE_CLEAN 0
205 #define STACKS_STATE_DIRTY 1
206 #define STACKS_STATE_DONE 2
207 static uint_t stacks_state = STACKS_STATE_CLEAN;
208 static stacks_entry_t **stacks_hash;
209 static stacks_entry_t **stacks_array;
210 static size_t stacks_array_size;
212 static size_t
213 stacks_hash_entry(stacks_entry_t *sep)
215 size_t depth = sep->se_depth;
216 uintptr_t *stack = sep->se_stack;
218 uint64_t total = depth;
220 while (depth > 0) {
221 total += *stack;
222 stack++; depth--;
225 return (total % STACKS_HSIZE);
229 * This is used to both compare stacks for equality and to sort the final
230 * list of unique stacks. forsort specifies the latter behavior, which
231 * additionally:
232 * compares se_count, and
233 * sorts the stacks by text function name.
235 * The equality test is independent of se_count, and doesn't care about
236 * relative ordering, so we don't do the extra work of looking up symbols
237 * for the stack addresses.
239 static int
240 stacks_entry_comp_impl(stacks_entry_t *l, stacks_entry_t *r,
241 uint_t forsort)
243 int idx;
245 int depth = MIN(l->se_depth, r->se_depth);
247 /* no matter what, panic stacks come last. */
248 if (l->se_panic > r->se_panic)
249 return (1);
250 if (l->se_panic < r->se_panic)
251 return (-1);
253 if (forsort) {
254 /* put large counts earlier */
255 if (l->se_count > r->se_count)
256 return (-1);
257 if (l->se_count < r->se_count)
258 return (1);
261 if (l->se_tstate > r->se_tstate)
262 return (1);
263 if (l->se_tstate < r->se_tstate)
264 return (-1);
266 if (l->se_failed > r->se_failed)
267 return (1);
268 if (l->se_failed < r->se_failed)
269 return (-1);
271 for (idx = 0; idx < depth; idx++) {
272 char lbuf[MDB_SYM_NAMLEN];
273 char rbuf[MDB_SYM_NAMLEN];
275 int rval;
276 uintptr_t laddr = l->se_stack[idx];
277 uintptr_t raddr = r->se_stack[idx];
279 if (laddr == raddr)
280 continue;
282 if (forsort &&
283 mdb_lookup_by_addr(laddr, MDB_SYM_FUZZY,
284 lbuf, sizeof (lbuf), NULL) != -1 &&
285 mdb_lookup_by_addr(raddr, MDB_SYM_FUZZY,
286 rbuf, sizeof (rbuf), NULL) != -1 &&
287 (rval = strcmp(lbuf, rbuf)) != 0)
288 return (rval);
290 if (laddr > raddr)
291 return (1);
292 return (-1);
295 if (l->se_overflow > r->se_overflow)
296 return (-1);
297 if (l->se_overflow < r->se_overflow)
298 return (1);
300 if (l->se_depth > r->se_depth)
301 return (1);
302 if (l->se_depth < r->se_depth)
303 return (-1);
305 if (l->se_sobj_ops > r->se_sobj_ops)
306 return (1);
307 if (l->se_sobj_ops < r->se_sobj_ops)
308 return (-1);
310 return (0);
313 static int
314 stacks_entry_comp(const void *l_arg, const void *r_arg)
316 stacks_entry_t * const *lp = l_arg;
317 stacks_entry_t * const *rp = r_arg;
319 return (stacks_entry_comp_impl(*lp, *rp, 1));
322 void
323 stacks_cleanup(int force)
325 int idx = 0;
326 stacks_entry_t *cur, *next;
328 if (stacks_state == STACKS_STATE_CLEAN)
329 return;
331 if (!force && stacks_state == STACKS_STATE_DONE)
332 return;
335 * Until the array is sorted and stable, stacks_hash will be non-NULL.
336 * This way, we can get at all of the data, even if qsort() was
337 * interrupted while mucking with the array.
339 if (stacks_hash != NULL) {
340 for (idx = 0; idx < STACKS_HSIZE; idx++) {
341 while ((cur = stacks_hash[idx]) != NULL) {
342 while ((next = cur->se_dup) != NULL) {
343 cur->se_dup = next->se_dup;
344 mdb_free(next,
345 STACKS_ENTRY_SIZE(next->se_depth));
347 next = cur->se_next;
348 stacks_hash[idx] = next;
349 mdb_free(cur, STACKS_ENTRY_SIZE(cur->se_depth));
352 if (stacks_array != NULL)
353 mdb_free(stacks_array,
354 stacks_array_size * sizeof (*stacks_array));
356 mdb_free(stacks_hash, STACKS_HSIZE * sizeof (*stacks_hash));
358 } else if (stacks_array != NULL) {
359 for (idx = 0; idx < stacks_array_size; idx++) {
360 if ((cur = stacks_array[idx]) != NULL) {
361 while ((next = cur->se_dup) != NULL) {
362 cur->se_dup = next->se_dup;
363 mdb_free(next,
364 STACKS_ENTRY_SIZE(next->se_depth));
366 stacks_array[idx] = NULL;
367 mdb_free(cur, STACKS_ENTRY_SIZE(cur->se_depth));
370 mdb_free(stacks_array,
371 stacks_array_size * sizeof (*stacks_array));
374 stacks_findstack_cleanup();
376 stacks_array_size = 0;
377 stacks_state = STACKS_STATE_CLEAN;
378 stacks_hash = NULL;
379 stacks_array = NULL;
382 /*ARGSUSED*/
383 static int
384 stacks_thread_cb(uintptr_t addr, const void *ignored, void *cbarg)
386 stacks_info_t *sip = cbarg;
387 findstack_info_t *fsip = &sip->si_fsi;
389 stacks_entry_t **sepp, *nsep, *sep;
390 int idx;
391 size_t depth;
393 if (stacks_findstack(addr, fsip, 0) != DCMD_OK &&
394 fsip->fsi_failed == FSI_FAIL_BADTHREAD) {
395 mdb_warn("couldn't read thread at %p\n", addr);
396 return (WALK_NEXT);
399 sip->si_count++;
401 depth = fsip->fsi_depth;
402 nsep = mdb_zalloc(STACKS_ENTRY_SIZE(depth), UM_SLEEP);
403 nsep->se_thread = addr;
404 nsep->se_sp = fsip->fsi_sp;
405 nsep->se_sobj_ops = fsip->fsi_sobj_ops;
406 nsep->se_tstate = fsip->fsi_tstate;
407 nsep->se_count = 1;
408 nsep->se_overflow = fsip->fsi_overflow;
409 nsep->se_depth = depth;
410 nsep->se_failed = fsip->fsi_failed;
411 nsep->se_panic = fsip->fsi_panic;
413 for (idx = 0; idx < depth; idx++)
414 nsep->se_stack[idx] = fsip->fsi_stack[idx];
416 for (sepp = &sip->si_hash[stacks_hash_entry(nsep)];
417 (sep = *sepp) != NULL;
418 sepp = &sep->se_next) {
420 if (stacks_entry_comp_impl(sep, nsep, 0) != 0)
421 continue;
423 nsep->se_dup = sep->se_dup;
424 sep->se_dup = nsep;
425 sep->se_count++;
426 return (WALK_NEXT);
429 nsep->se_next = NULL;
430 *sepp = nsep;
431 sip->si_entries++;
433 return (WALK_NEXT);
436 static int
437 stacks_run_tlist(mdb_pipe_t *tlist, stacks_info_t *si)
439 size_t idx;
440 size_t found = 0;
441 int ret;
443 for (idx = 0; idx < tlist->pipe_len; idx++) {
444 uintptr_t addr = tlist->pipe_data[idx];
446 found++;
448 ret = stacks_thread_cb(addr, NULL, si);
449 if (ret == WALK_DONE)
450 break;
451 if (ret != WALK_NEXT)
452 return (-1);
455 if (found)
456 return (0);
457 return (-1);
460 static int
461 stacks_run(int verbose, mdb_pipe_t *tlist)
463 stacks_info_t si;
464 findstack_info_t *fsip = &si.si_fsi;
465 size_t idx;
466 stacks_entry_t **cur;
468 bzero(&si, sizeof (si));
470 stacks_state = STACKS_STATE_DIRTY;
472 stacks_hash = si.si_hash =
473 mdb_zalloc(STACKS_HSIZE * sizeof (*si.si_hash), UM_SLEEP);
474 si.si_entries = 0;
475 si.si_count = 0;
477 fsip->fsi_max_depth = STACKS_MAX_DEPTH;
478 fsip->fsi_stack =
479 mdb_alloc(fsip->fsi_max_depth * sizeof (*fsip->fsi_stack),
480 UM_SLEEP | UM_GC);
482 if (verbose)
483 mdb_warn("stacks: processing kernel threads\n");
485 if (tlist != NULL) {
486 if (stacks_run_tlist(tlist, &si))
487 return (DCMD_ERR);
488 } else {
489 if (mdb_walk("thread", stacks_thread_cb, &si) != 0) {
490 mdb_warn("cannot walk \"thread\"");
491 return (DCMD_ERR);
495 if (verbose)
496 mdb_warn("stacks: %d unique stacks / %d threads\n",
497 si.si_entries, si.si_count);
499 stacks_array_size = si.si_entries;
500 stacks_array =
501 mdb_zalloc(si.si_entries * sizeof (*stacks_array), UM_SLEEP);
502 cur = stacks_array;
503 for (idx = 0; idx < STACKS_HSIZE; idx++) {
504 stacks_entry_t *sep;
505 for (sep = si.si_hash[idx]; sep != NULL; sep = sep->se_next)
506 *(cur++) = sep;
509 if (cur != stacks_array + si.si_entries) {
510 mdb_warn("stacks: miscounted array size (%d != size: %d)\n",
511 (cur - stacks_array), stacks_array_size);
512 return (DCMD_ERR);
514 qsort(stacks_array, si.si_entries, sizeof (*stacks_array),
515 stacks_entry_comp);
517 /* Now that we're done, free the hash table */
518 stacks_hash = NULL;
519 mdb_free(si.si_hash, STACKS_HSIZE * sizeof (*si.si_hash));
521 if (tlist == NULL)
522 stacks_state = STACKS_STATE_DONE;
524 if (verbose)
525 mdb_warn("stacks: done\n");
527 return (DCMD_OK);
530 static int
531 stacks_has_caller(stacks_entry_t *sep, uintptr_t addr)
533 uintptr_t laddr = addr;
534 uintptr_t haddr = addr + 1;
535 int idx;
536 char c[MDB_SYM_NAMLEN];
537 GElf_Sym sym;
539 if (mdb_lookup_by_addr(addr, MDB_SYM_FUZZY,
540 c, sizeof (c), &sym) != -1 &&
541 addr == (uintptr_t)sym.st_value) {
542 laddr = (uintptr_t)sym.st_value;
543 haddr = (uintptr_t)sym.st_value + sym.st_size;
546 for (idx = 0; idx < sep->se_depth; idx++)
547 if (sep->se_stack[idx] >= laddr && sep->se_stack[idx] < haddr)
548 return (1);
550 return (0);
553 static int
554 stacks_has_module(stacks_entry_t *sep, stacks_module_t *mp)
556 int idx;
558 for (idx = 0; idx < sep->se_depth; idx++) {
559 if (sep->se_stack[idx] >= mp->sm_text &&
560 sep->se_stack[idx] < mp->sm_text + mp->sm_size)
561 return (1);
564 return (0);
567 static int
568 stacks_module_find(const char *name, stacks_module_t *mp)
570 (void) strncpy(mp->sm_name, name, sizeof (mp->sm_name));
572 if (stacks_module(mp) != 0)
573 return (-1);
575 if (mp->sm_size == 0) {
576 mdb_warn("stacks: module \"%s\" is unknown\n", name);
577 return (-1);
580 return (0);
583 static int
584 uintptrcomp(const void *lp, const void *rp)
586 uintptr_t lhs = *(const uintptr_t *)lp;
587 uintptr_t rhs = *(const uintptr_t *)rp;
588 if (lhs > rhs)
589 return (1);
590 if (lhs < rhs)
591 return (-1);
592 return (0);
595 /*ARGSUSED*/
597 stacks(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
599 size_t idx;
601 char *seen = NULL;
603 const char *caller_str = NULL;
604 const char *excl_caller_str = NULL;
605 uintptr_t caller = 0, excl_caller = 0;
606 const char *module_str = NULL;
607 const char *excl_module_str = NULL;
608 stacks_module_t module, excl_module;
609 const char *sobj = NULL;
610 const char *excl_sobj = NULL;
611 uintptr_t sobj_ops = 0, excl_sobj_ops = 0;
612 const char *tstate_str = NULL;
613 const char *excl_tstate_str = NULL;
614 uint_t tstate = -1U;
615 uint_t excl_tstate = -1U;
616 uint_t printed = 0;
618 uint_t all = 0;
619 uint_t force = 0;
620 uint_t interesting = 0;
621 uint_t verbose = 0;
624 * We have a slight behavior difference between having piped
625 * input and 'addr::stacks'. Without a pipe, we assume the
626 * thread pointer given is a representative thread, and so
627 * we include all similar threads in the system in our output.
629 * With a pipe, we filter down to just the threads in our
630 * input.
632 uint_t addrspec = (flags & DCMD_ADDRSPEC);
633 uint_t only_matching = addrspec && (flags & DCMD_PIPE);
635 mdb_pipe_t p;
637 bzero(&module, sizeof (module));
638 bzero(&excl_module, sizeof (excl_module));
640 if (mdb_getopts(argc, argv,
641 'a', MDB_OPT_SETBITS, TRUE, &all,
642 'f', MDB_OPT_SETBITS, TRUE, &force,
643 'i', MDB_OPT_SETBITS, TRUE, &interesting,
644 'v', MDB_OPT_SETBITS, TRUE, &verbose,
645 'c', MDB_OPT_STR, &caller_str,
646 'C', MDB_OPT_STR, &excl_caller_str,
647 'm', MDB_OPT_STR, &module_str,
648 'M', MDB_OPT_STR, &excl_module_str,
649 's', MDB_OPT_STR, &sobj,
650 'S', MDB_OPT_STR, &excl_sobj,
651 't', MDB_OPT_STR, &tstate_str,
652 'T', MDB_OPT_STR, &excl_tstate_str,
653 NULL) != argc)
654 return (DCMD_USAGE);
656 if (interesting) {
657 if (sobj != NULL || excl_sobj != NULL ||
658 tstate_str != NULL || excl_tstate_str != NULL) {
659 mdb_warn(
660 "stacks: -i is incompatible with -[sStT]\n");
661 return (DCMD_USAGE);
663 excl_sobj = "CV";
664 excl_tstate_str = "FREE";
667 if (caller_str != NULL) {
668 mdb_set_dot(0);
669 if (mdb_eval(caller_str) != 0) {
670 mdb_warn("stacks: evaluation of \"%s\" failed",
671 caller_str);
672 return (DCMD_ABORT);
674 caller = mdb_get_dot();
677 if (excl_caller_str != NULL) {
678 mdb_set_dot(0);
679 if (mdb_eval(excl_caller_str) != 0) {
680 mdb_warn("stacks: evaluation of \"%s\" failed",
681 excl_caller_str);
682 return (DCMD_ABORT);
684 excl_caller = mdb_get_dot();
686 mdb_set_dot(addr);
688 if (module_str != NULL && stacks_module_find(module_str, &module) != 0)
689 return (DCMD_ABORT);
691 if (excl_module_str != NULL &&
692 stacks_module_find(excl_module_str, &excl_module) != 0)
693 return (DCMD_ABORT);
695 if (sobj != NULL && text_to_sobj(sobj, &sobj_ops) != 0)
696 return (DCMD_USAGE);
698 if (excl_sobj != NULL && text_to_sobj(excl_sobj, &excl_sobj_ops) != 0)
699 return (DCMD_USAGE);
701 if (sobj_ops != 0 && excl_sobj_ops != 0) {
702 mdb_warn("stacks: only one of -s and -S can be specified\n");
703 return (DCMD_USAGE);
706 if (tstate_str != NULL && text_to_tstate(tstate_str, &tstate) != 0)
707 return (DCMD_USAGE);
709 if (excl_tstate_str != NULL &&
710 text_to_tstate(excl_tstate_str, &excl_tstate) != 0)
711 return (DCMD_USAGE);
713 if (tstate != -1U && excl_tstate != -1U) {
714 mdb_warn("stacks: only one of -t and -T can be specified\n");
715 return (DCMD_USAGE);
719 * If there's an address specified, we're going to further filter
720 * to only entries which have an address in the input. To reduce
721 * overhead (and make the sorted output come out right), we
722 * use mdb_get_pipe() to grab the entire pipeline of input, then
723 * use qsort() and bsearch() to speed up the search.
725 if (addrspec) {
726 mdb_get_pipe(&p);
727 if (p.pipe_data == NULL || p.pipe_len == 0) {
728 p.pipe_data = &addr;
729 p.pipe_len = 1;
731 qsort(p.pipe_data, p.pipe_len, sizeof (uintptr_t),
732 uintptrcomp);
734 /* remove any duplicates in the data */
735 idx = 0;
736 while (idx < p.pipe_len - 1) {
737 uintptr_t *data = &p.pipe_data[idx];
738 size_t len = p.pipe_len - idx;
740 if (data[0] == data[1]) {
741 memmove(data, data + 1,
742 (len - 1) * sizeof (*data));
743 p.pipe_len--;
744 continue; /* repeat without incrementing idx */
746 idx++;
749 seen = mdb_zalloc(p.pipe_len, UM_SLEEP | UM_GC);
753 * Force a cleanup if we're connected to a live system. Never
754 * do a cleanup after the first invocation around the loop.
756 force |= (mdb_get_state() == MDB_STATE_RUNNING);
757 if (force && (flags & (DCMD_LOOPFIRST|DCMD_LOOP)) == DCMD_LOOP)
758 force = 0;
760 stacks_cleanup(force);
762 if (stacks_state == STACKS_STATE_CLEAN) {
763 int res = stacks_run(verbose, addrspec ? &p : NULL);
764 if (res != DCMD_OK)
765 return (res);
768 for (idx = 0; idx < stacks_array_size; idx++) {
769 stacks_entry_t *sep = stacks_array[idx];
770 stacks_entry_t *cur = sep;
771 int frame;
772 size_t count = sep->se_count;
774 if (addrspec) {
775 stacks_entry_t *head = NULL, *tail = NULL, *sp;
776 size_t foundcount = 0;
778 * We use the now-unused hash chain field se_next to
779 * link together the dups which match our list.
781 for (sp = sep; sp != NULL; sp = sp->se_dup) {
782 uintptr_t *entry = bsearch(&sp->se_thread,
783 p.pipe_data, p.pipe_len, sizeof (uintptr_t),
784 uintptrcomp);
785 if (entry != NULL) {
786 foundcount++;
787 seen[entry - p.pipe_data]++;
788 if (head == NULL)
789 head = sp;
790 else
791 tail->se_next = sp;
792 tail = sp;
793 sp->se_next = NULL;
796 if (head == NULL)
797 continue; /* no match, skip entry */
799 if (only_matching) {
800 cur = sep = head;
801 count = foundcount;
805 if (caller != 0 && !stacks_has_caller(sep, caller))
806 continue;
808 if (excl_caller != 0 && stacks_has_caller(sep, excl_caller))
809 continue;
811 if (module.sm_size != 0 && !stacks_has_module(sep, &module))
812 continue;
814 if (excl_module.sm_size != 0 &&
815 stacks_has_module(sep, &excl_module))
816 continue;
818 if (tstate != -1U) {
819 if (tstate == TSTATE_PANIC) {
820 if (!sep->se_panic)
821 continue;
822 } else if (sep->se_panic || sep->se_tstate != tstate)
823 continue;
825 if (excl_tstate != -1U) {
826 if (excl_tstate == TSTATE_PANIC) {
827 if (sep->se_panic)
828 continue;
829 } else if (!sep->se_panic &&
830 sep->se_tstate == excl_tstate)
831 continue;
834 if (sobj_ops == SOBJ_ALL) {
835 if (sep->se_sobj_ops == 0)
836 continue;
837 } else if (sobj_ops != 0) {
838 if (sobj_ops != sep->se_sobj_ops)
839 continue;
842 if (!(interesting && sep->se_panic)) {
843 if (excl_sobj_ops == SOBJ_ALL) {
844 if (sep->se_sobj_ops != 0)
845 continue;
846 } else if (excl_sobj_ops != 0) {
847 if (excl_sobj_ops == sep->se_sobj_ops)
848 continue;
852 if (flags & DCMD_PIPE_OUT) {
853 while (sep != NULL) {
854 mdb_printf("%lr\n", sep->se_thread);
855 sep = only_matching ?
856 sep->se_next : sep->se_dup;
858 continue;
861 if (all || !printed) {
862 mdb_printf("%<u>%-?s %-8s %-?s %8s%</u>\n",
863 "THREAD", "STATE", "SOBJ", "COUNT");
864 printed = 1;
867 do {
868 char state[20];
869 char sobj[100];
871 tstate_to_text(cur->se_tstate, cur->se_panic,
872 state, sizeof (state));
873 sobj_to_text(cur->se_sobj_ops,
874 sobj, sizeof (sobj));
876 if (cur == sep)
877 mdb_printf("%-?p %-8s %-?s %8d\n",
878 cur->se_thread, state, sobj, count);
879 else
880 mdb_printf("%-?p %-8s %-?s %8s\n",
881 cur->se_thread, state, sobj, "-");
883 cur = only_matching ? cur->se_next : cur->se_dup;
884 } while (all && cur != NULL);
886 if (sep->se_failed != 0) {
887 char *reason;
888 switch (sep->se_failed) {
889 case FSI_FAIL_NOTINMEMORY:
890 reason = "thread not in memory";
891 break;
892 case FSI_FAIL_THREADCORRUPT:
893 reason = "thread structure stack info corrupt";
894 break;
895 case FSI_FAIL_STACKNOTFOUND:
896 reason = "no consistent stack found";
897 break;
898 default:
899 reason = "unknown failure";
900 break;
902 mdb_printf("%?s <%s>\n", "", reason);
905 for (frame = 0; frame < sep->se_depth; frame++)
906 mdb_printf("%?s %a\n", "", sep->se_stack[frame]);
907 if (sep->se_overflow)
908 mdb_printf("%?s ... truncated ...\n", "");
909 mdb_printf("\n");
912 if (flags & DCMD_ADDRSPEC) {
913 for (idx = 0; idx < p.pipe_len; idx++)
914 if (seen[idx] == 0)
915 mdb_warn("stacks: %p not in thread list\n",
916 p.pipe_data[idx]);
918 return (DCMD_OK);