xref: /illumos-gate/usr/src/cmd/mdb/common/modules/genunix/findstack.c (revision 3350c9c925acb5854315e9d992703db756886095)
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
print_stack(uintptr_t sp,uintptr_t pc,uintptr_t addr,int argc,const mdb_arg_t * argv,int free_state)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
findstack(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
findstack_debug(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * av)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
uppercase(char * p)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
sobj_to_text(uintptr_t addr,char * out,size_t out_sz)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
text_to_sobj(const char * text,uintptr_t * out)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
text_to_tstate(const char * text,uint_t * out)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
tstate_to_text(uint_t tstate,uint_t paniced,char * out,size_t out_sz)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
stacks_hash_entry(stacks_entry_t * sep)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
stacks_entry_comp_impl(stacks_entry_t * l,stacks_entry_t * r,uint_t forsort)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
stacks_entry_comp(const void * l_arg,const void * r_arg)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
stacks_cleanup(int force)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
stacks_thread_cb(uintptr_t addr,const void * ignored,void * cbarg)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
stacks_run_tlist(mdb_pipe_t * tlist,stacks_info_t * si)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
stacks_run(int verbose,mdb_pipe_t * tlist)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
stacks_has_caller(stacks_entry_t * sep,uintptr_t addr)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
stacks_has_module(stacks_entry_t * sep,stacks_module_t * mp)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
stacks_module_find(const char * name,stacks_module_t * mp)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
uintptrcomp(const void * lp,const void * rp)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
stacks(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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