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]
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>
38 #include "findstack.h"
43 * Parts of this file are shared between targets, but this section is only
44 * used for KVM and KMDB.
48 int findstack_debug_on
= 0;
51 * "sp" is a kernel VA.
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
;
60 count
= mdb_getopts(argc
, argv
,
61 'v', MDB_OPT_SETBITS
, TRUE
, &showargs
, NULL
);
65 if (argc
> 1 || (argc
== 1 && argv
->a_type
!= MDB_TYPE_STRING
))
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
);
73 mdb_printf("[ %0?lr %a() ]\n", sp
, pc
);
79 err
= mdb_eval(argv
->a_un
.a_str
);
81 err
= mdb_eval("<.$C");
83 err
= mdb_eval("<.$C0");
87 return ((err
== -1) ? DCMD_ABORT
: DCMD_OK
);
91 findstack(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
96 if (!(flags
& DCMD_ADDRSPEC
))
99 bzero(&fsi
, sizeof (fsi
));
101 if ((retval
= stacks_findstack(addr
, &fsi
, 1)) != DCMD_OK
||
105 return (print_stack(fsi
.fsi_sp
, fsi
.fsi_pc
, addr
,
106 argc
, argv
, fsi
.fsi_tstate
== TS_FREE
));
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");
126 for (; *p
!= '\0'; p
++) {
127 if (*p
>= 'a' && *p
<= 'z')
133 sobj_to_text(uintptr_t addr
, char *out
, size_t out_sz
)
135 sobj_ops_to_text(addr
, out
, out_sz
);
142 text_to_sobj(const char *text
, uintptr_t *out
)
144 if (strcasecmp(text
, "ALL") == 0) {
149 return (sobj_text_to_ops(text
, out
));
152 #define TSTATE_PANIC -2U
154 text_to_tstate(const char *text
, uint_t
*out
)
156 if (strcasecmp(text
, "panic") == 0)
158 else if (thread_text_to_state(text
, out
) != 0) {
159 mdb_warn("tstate \"%s\" not recognized\n", text
);
166 tstate_to_text(uint_t tstate
, uint_t paniced
, char *out
, size_t out_sz
)
169 mdb_snprintf(out
, out_sz
, "panic");
171 thread_state_to_text(tstate
, out
, out_sz
);
175 typedef struct stacks_entry
{
176 struct stacks_entry
*se_next
;
177 struct stacks_entry
*se_dup
; /* dups of this stack */
180 uintptr_t se_sobj_ops
;
182 uint32_t se_count
; /* # threads w/ this stack */
185 uint8_t se_failed
; /* failure reason; FSI_FAIL_* */
187 uintptr_t se_stack
[1];
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 */
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
;
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
;
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
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.
240 stacks_entry_comp_impl(stacks_entry_t
*l
, stacks_entry_t
*r
,
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
)
250 if (l
->se_panic
< r
->se_panic
)
254 /* put large counts earlier */
255 if (l
->se_count
> r
->se_count
)
257 if (l
->se_count
< r
->se_count
)
261 if (l
->se_tstate
> r
->se_tstate
)
263 if (l
->se_tstate
< r
->se_tstate
)
266 if (l
->se_failed
> r
->se_failed
)
268 if (l
->se_failed
< r
->se_failed
)
271 for (idx
= 0; idx
< depth
; idx
++) {
272 char lbuf
[MDB_SYM_NAMLEN
];
273 char rbuf
[MDB_SYM_NAMLEN
];
276 uintptr_t laddr
= l
->se_stack
[idx
];
277 uintptr_t raddr
= r
->se_stack
[idx
];
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)
295 if (l
->se_overflow
> r
->se_overflow
)
297 if (l
->se_overflow
< r
->se_overflow
)
300 if (l
->se_depth
> r
->se_depth
)
302 if (l
->se_depth
< r
->se_depth
)
305 if (l
->se_sobj_ops
> r
->se_sobj_ops
)
307 if (l
->se_sobj_ops
< r
->se_sobj_ops
)
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));
323 stacks_cleanup(int force
)
326 stacks_entry_t
*cur
, *next
;
328 if (stacks_state
== STACKS_STATE_CLEAN
)
331 if (!force
&& stacks_state
== STACKS_STATE_DONE
)
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
;
345 STACKS_ENTRY_SIZE(next
->se_depth
));
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
;
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
;
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
;
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
);
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
;
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)
423 nsep
->se_dup
= sep
->se_dup
;
429 nsep
->se_next
= NULL
;
437 stacks_run_tlist(mdb_pipe_t
*tlist
, stacks_info_t
*si
)
443 for (idx
= 0; idx
< tlist
->pipe_len
; idx
++) {
444 uintptr_t addr
= tlist
->pipe_data
[idx
];
448 ret
= stacks_thread_cb(addr
, NULL
, si
);
449 if (ret
== WALK_DONE
)
451 if (ret
!= WALK_NEXT
)
461 stacks_run(int verbose
, mdb_pipe_t
*tlist
)
464 findstack_info_t
*fsip
= &si
.si_fsi
;
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
);
477 fsip
->fsi_max_depth
= STACKS_MAX_DEPTH
;
479 mdb_alloc(fsip
->fsi_max_depth
* sizeof (*fsip
->fsi_stack
),
483 mdb_warn("stacks: processing kernel threads\n");
486 if (stacks_run_tlist(tlist
, &si
))
489 if (mdb_walk("thread", stacks_thread_cb
, &si
) != 0) {
490 mdb_warn("cannot walk \"thread\"");
496 mdb_warn("stacks: %d unique stacks / %d threads\n",
497 si
.si_entries
, si
.si_count
);
499 stacks_array_size
= si
.si_entries
;
501 mdb_zalloc(si
.si_entries
* sizeof (*stacks_array
), UM_SLEEP
);
503 for (idx
= 0; idx
< STACKS_HSIZE
; idx
++) {
505 for (sep
= si
.si_hash
[idx
]; sep
!= NULL
; sep
= sep
->se_next
)
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
);
514 qsort(stacks_array
, si
.si_entries
, sizeof (*stacks_array
),
517 /* Now that we're done, free the hash table */
519 mdb_free(si
.si_hash
, STACKS_HSIZE
* sizeof (*si
.si_hash
));
522 stacks_state
= STACKS_STATE_DONE
;
525 mdb_warn("stacks: done\n");
531 stacks_has_caller(stacks_entry_t
*sep
, uintptr_t addr
)
533 uintptr_t laddr
= addr
;
534 uintptr_t haddr
= addr
+ 1;
536 char c
[MDB_SYM_NAMLEN
];
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
)
554 stacks_has_module(stacks_entry_t
*sep
, stacks_module_t
*mp
)
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
)
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)
575 if (mp
->sm_size
== 0) {
576 mdb_warn("stacks: module \"%s\" is unknown\n", name
);
584 uintptrcomp(const void *lp
, const void *rp
)
586 uintptr_t lhs
= *(const uintptr_t *)lp
;
587 uintptr_t rhs
= *(const uintptr_t *)rp
;
597 stacks(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
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
;
615 uint_t excl_tstate
= -1U;
620 uint_t interesting
= 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
632 uint_t addrspec
= (flags
& DCMD_ADDRSPEC
);
633 uint_t only_matching
= addrspec
&& (flags
& DCMD_PIPE
);
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
,
657 if (sobj
!= NULL
|| excl_sobj
!= NULL
||
658 tstate_str
!= NULL
|| excl_tstate_str
!= NULL
) {
660 "stacks: -i is incompatible with -[sStT]\n");
664 excl_tstate_str
= "FREE";
667 if (caller_str
!= NULL
) {
669 if (mdb_eval(caller_str
) != 0) {
670 mdb_warn("stacks: evaluation of \"%s\" failed",
674 caller
= mdb_get_dot();
677 if (excl_caller_str
!= NULL
) {
679 if (mdb_eval(excl_caller_str
) != 0) {
680 mdb_warn("stacks: evaluation of \"%s\" failed",
684 excl_caller
= mdb_get_dot();
688 if (module_str
!= NULL
&& stacks_module_find(module_str
, &module
) != 0)
691 if (excl_module_str
!= NULL
&&
692 stacks_module_find(excl_module_str
, &excl_module
) != 0)
695 if (sobj
!= NULL
&& text_to_sobj(sobj
, &sobj_ops
) != 0)
698 if (excl_sobj
!= NULL
&& text_to_sobj(excl_sobj
, &excl_sobj_ops
) != 0)
701 if (sobj_ops
!= 0 && excl_sobj_ops
!= 0) {
702 mdb_warn("stacks: only one of -s and -S can be specified\n");
706 if (tstate_str
!= NULL
&& text_to_tstate(tstate_str
, &tstate
) != 0)
709 if (excl_tstate_str
!= NULL
&&
710 text_to_tstate(excl_tstate_str
, &excl_tstate
) != 0)
713 if (tstate
!= -1U && excl_tstate
!= -1U) {
714 mdb_warn("stacks: only one of -t and -T can be specified\n");
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.
727 if (p
.pipe_data
== NULL
|| p
.pipe_len
== 0) {
731 qsort(p
.pipe_data
, p
.pipe_len
, sizeof (uintptr_t),
734 /* remove any duplicates in the data */
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
));
744 continue; /* repeat without incrementing 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
)
760 stacks_cleanup(force
);
762 if (stacks_state
== STACKS_STATE_CLEAN
) {
763 int res
= stacks_run(verbose
, addrspec
? &p
: NULL
);
768 for (idx
= 0; idx
< stacks_array_size
; idx
++) {
769 stacks_entry_t
*sep
= stacks_array
[idx
];
770 stacks_entry_t
*cur
= sep
;
772 size_t count
= sep
->se_count
;
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),
787 seen
[entry
- p
.pipe_data
]++;
797 continue; /* no match, skip entry */
805 if (caller
!= 0 && !stacks_has_caller(sep
, caller
))
808 if (excl_caller
!= 0 && stacks_has_caller(sep
, excl_caller
))
811 if (module
.sm_size
!= 0 && !stacks_has_module(sep
, &module
))
814 if (excl_module
.sm_size
!= 0 &&
815 stacks_has_module(sep
, &excl_module
))
819 if (tstate
== TSTATE_PANIC
) {
822 } else if (sep
->se_panic
|| sep
->se_tstate
!= tstate
)
825 if (excl_tstate
!= -1U) {
826 if (excl_tstate
== TSTATE_PANIC
) {
829 } else if (!sep
->se_panic
&&
830 sep
->se_tstate
== excl_tstate
)
834 if (sobj_ops
== SOBJ_ALL
) {
835 if (sep
->se_sobj_ops
== 0)
837 } else if (sobj_ops
!= 0) {
838 if (sobj_ops
!= sep
->se_sobj_ops
)
842 if (!(interesting
&& sep
->se_panic
)) {
843 if (excl_sobj_ops
== SOBJ_ALL
) {
844 if (sep
->se_sobj_ops
!= 0)
846 } else if (excl_sobj_ops
!= 0) {
847 if (excl_sobj_ops
== sep
->se_sobj_ops
)
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
;
861 if (all
|| !printed
) {
862 mdb_printf("%<u>%-?s %-8s %-?s %8s%</u>\n",
863 "THREAD", "STATE", "SOBJ", "COUNT");
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
));
877 mdb_printf("%-?p %-8s %-?s %8d\n",
878 cur
->se_thread
, state
, sobj
, count
);
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) {
888 switch (sep
->se_failed
) {
889 case FSI_FAIL_NOTINMEMORY
:
890 reason
= "thread not in memory";
892 case FSI_FAIL_THREADCORRUPT
:
893 reason
= "thread structure stack info corrupt";
895 case FSI_FAIL_STACKNOTFOUND
:
896 reason
= "no consistent stack found";
899 reason
= "unknown failure";
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", "");
912 if (flags
& DCMD_ADDRSPEC
) {
913 for (idx
= 0; idx
< p
.pipe_len
; idx
++)
915 mdb_warn("stacks: %p not in thread list\n",