xref: /illumos-gate/usr/src/cmd/mdb/common/modules/genunix/findstack.c (revision 3fb2fe9fdd2e33737038a161631f2ab6d7050ecf)
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