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