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) 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <mdb/mdb_modapi.h>
32 #include <thr_uberdata.h>
34 #include "findstack.h"
36 #if defined(__i386) || defined(__amd64)
48 #define STACKS_REGS_FP "rbp"
49 #define STACKS_REGS_RC "rip"
52 #define STACKS_REGS_FP "ebp"
53 #define STACKS_REGS_RC "eip"
55 #define STACKS_REGS_FP "fp"
56 #define STACKS_REGS_RC "pc"
60 #define STACKS_SOBJ_MX (uintptr_t)"MX"
61 #define STACKS_SOBJ_CV (uintptr_t)"CV"
64 thread_text_to_state(const char *state
, uint_t
*out
)
66 if (strcmp(state
, "PARKED") == 0) {
68 } else if (strcmp(state
, "UNPARKED") == 0) {
70 } else if (strcmp(state
, "FREE") == 0) {
72 * When run with "-i", ::stacks filters out "FREE" threads.
73 * We therefore need to recognize "FREE", and set it to a
74 * value that will never match fsi_tstate.
85 thread_state_to_text(uint_t state
, char *out
, size_t out_sz
)
87 (void) snprintf(out
, out_sz
, state
? "PARKED" : "UNPARKED");
91 sobj_text_to_ops(const char *name
, uintptr_t *sobj_ops_out
)
93 if (strcmp(name
, "MX") == 0) {
94 *sobj_ops_out
= STACKS_SOBJ_MX
;
95 } else if (strcmp(name
, "CV") == 0) {
96 *sobj_ops_out
= STACKS_SOBJ_CV
;
98 mdb_warn("sobj \"%s\" not recognized\n", name
);
106 sobj_ops_to_text(uintptr_t addr
, char *out
, size_t sz
)
108 (void) snprintf(out
, sz
, "%s", addr
== NULL
? "<none>" : (char *)addr
);
112 stacks_module_callback(mdb_object_t
*obj
, void *arg
)
114 stacks_module_t
*smp
= arg
;
115 boolean_t match
= (strcmp(obj
->obj_name
, smp
->sm_name
) == 0);
116 char *suffix
= ".so";
117 const char *s
, *next
;
120 if (smp
->sm_size
!= 0)
124 * It doesn't match the name, but -- for convenience -- we want to
125 * allow matches before ".so.[suffix]". An aside: why doesn't
126 * strrstr() exist? (Don't google that. I'm serious, don't do it.
127 * If you do, and you read the thread of "why doesn't strrstr() exist?"
128 * circa 2005 you will see things that you will NEVER be able to unsee!)
130 if (!match
&& (s
= strstr(obj
->obj_name
, suffix
)) != NULL
) {
131 while ((next
= strstr(s
+ 1, suffix
)) != NULL
) {
136 len
= s
- obj
->obj_name
;
138 match
= (strncmp(smp
->sm_name
, obj
->obj_name
, len
) == 0 &&
139 smp
->sm_name
[len
] == '\0');
143 * If we have a library that has the libc directory in the path, we
144 * want to match against anything that would match libc.so.1. (This
145 * is necessary to be able to easily deal with libc implementations
146 * that have alternate hardware capabilities.)
148 if (!match
&& strstr(obj
->obj_fullname
, "/libc/") != NULL
) {
149 mdb_object_t libc
= *obj
;
151 libc
.obj_name
= "libc.so.1";
152 libc
.obj_fullname
= "";
154 return (stacks_module_callback(&libc
, arg
));
158 smp
->sm_text
= obj
->obj_base
;
159 smp
->sm_size
= obj
->obj_size
;
166 stacks_module(stacks_module_t
*smp
)
168 if (mdb_object_iter(stacks_module_callback
, smp
) != 0)
174 typedef struct stacks_ulwp
{
175 avl_node_t sulwp_node
;
177 uintptr_t sulwp_addr
;
180 boolean_t stacks_ulwp_initialized
;
181 avl_tree_t stacks_ulwp_byid
;
185 stacks_ulwp_walk(uintptr_t addr
, ulwp_t
*ulwp
, void *ignored
)
187 stacks_ulwp_t
*sulwp
= mdb_alloc(sizeof (stacks_ulwp_t
), UM_SLEEP
);
189 sulwp
->sulwp_id
= ulwp
->ul_lwpid
;
190 sulwp
->sulwp_addr
= addr
;
192 if (avl_find(&stacks_ulwp_byid
, sulwp
, NULL
) != NULL
) {
193 mdb_warn("found multiple LWPs with ID %d!", ulwp
->ul_lwpid
);
197 avl_add(&stacks_ulwp_byid
, sulwp
);
203 stacks_ulwp_compare(const void *l
, const void *r
)
205 const stacks_ulwp_t
*lhs
= l
;
206 const stacks_ulwp_t
*rhs
= r
;
208 if (lhs
->sulwp_id
> rhs
->sulwp_id
)
211 if (lhs
->sulwp_id
< rhs
->sulwp_id
)
219 stacks_findstack(uintptr_t addr
, findstack_info_t
*fsip
, uint_t print_warnings
)
223 struct rwindow frame
;
224 avl_tree_t
*tree
= &stacks_ulwp_byid
;
225 stacks_ulwp_t
*sulwp
, cmp
;
228 fsip
->fsi_failed
= 0;
232 fsip
->fsi_overflow
= 0;
234 if (!stacks_ulwp_initialized
) {
235 avl_create(tree
, stacks_ulwp_compare
, sizeof (stacks_ulwp_t
),
236 offsetof(stacks_ulwp_t
, sulwp_node
));
239 (mdb_walk_cb_t
)stacks_ulwp_walk
, NULL
) != 0) {
240 mdb_warn("couldn't walk 'ulwp'");
244 stacks_ulwp_initialized
= B_TRUE
;
247 bzero(&cmp
, sizeof (cmp
));
248 cmp
.sulwp_id
= (lwpid_t
)addr
;
250 if ((sulwp
= avl_find(tree
, &cmp
, NULL
)) == NULL
) {
251 mdb_warn("couldn't find ulwp_t for tid %d\n", cmp
.sulwp_id
);
255 if (mdb_vread(&ulwp
, sizeof (ulwp
), sulwp
->sulwp_addr
) == -1) {
256 mdb_warn("couldn't read ulwp_t for tid %d at %p",
257 cmp
.sulwp_id
, sulwp
->sulwp_addr
);
261 fsip
->fsi_tstate
= ulwp
.ul_sleepq
!= NULL
;
262 fsip
->fsi_sobj_ops
= (uintptr_t)(ulwp
.ul_sleepq
== NULL
? NULL
:
263 (ulwp
.ul_qtype
== MX
? STACKS_SOBJ_MX
: STACKS_SOBJ_CV
));
265 if (mdb_getareg(addr
, STACKS_REGS_FP
, ®
) != 0) {
266 mdb_warn("couldn't read frame pointer for thread 0x%p", addr
);
270 fsip
->fsi_sp
= fp
= (uintptr_t)reg
;
273 if (mdb_getareg(addr
, STACKS_REGS_RC
, ®
) != 0) {
274 mdb_warn("couldn't read program counter for thread 0x%p", addr
);
278 fsip
->fsi_pc
= (uintptr_t)reg
;
282 if (mdb_vread(&frame
, sizeof (frame
), fp
) == -1) {
283 mdb_warn("couldn't read frame for thread 0x%p at %p",
288 if (frame
.rw_rtn
== NULL
)
291 if (fsip
->fsi_depth
< fsip
->fsi_max_depth
) {
292 fsip
->fsi_stack
[fsip
->fsi_depth
++] = frame
.rw_rtn
;
294 fsip
->fsi_overflow
= 1;
298 fp
= frame
.rw_fp
+ STACK_BIAS
;
305 stacks_findstack_cleanup()
307 avl_tree_t
*tree
= &stacks_ulwp_byid
;
309 stacks_ulwp_t
*sulwp
;
311 if (!stacks_ulwp_initialized
)
314 while ((sulwp
= avl_destroy_nodes(tree
, &cookie
)) != NULL
)
315 mdb_free(sulwp
, sizeof (stacks_ulwp_t
));
317 bzero(tree
, sizeof (*tree
));
318 stacks_ulwp_initialized
= B_FALSE
;
325 "::stacks processes all of the thread stacks in the process, grouping\n"
326 "together threads which have the same:\n"
329 " * Sync object type, and\n"
330 " * PCs in their stack trace.\n"
332 "The default output (no address or options) is just a dump of the thread\n"
333 "groups in the process. For a view of active threads, use \"::stacks -i\",\n"
334 "which filters out threads sleeping on a CV. More general filtering options\n"
335 "are described below, in the \"FILTERS\" section.\n"
337 "::stacks can be used in a pipeline. The input to ::stacks is one or more\n"
338 "thread IDs. When output into a pipe, ::stacks prints all of the threads \n"
339 "input, filtered by the given filtering options. This means that multiple\n"
340 "::stacks invocations can be piped together to achieve more complicated\n"
341 "filters. For example, to get threads which have both '__door_return' and\n"
342 "'mutex_lock' in their stack trace, you could do:\n"
344 " ::stacks -c __door_return | ::stacks -c mutex_lock\n"
346 "To get the full list of threads in each group, use the '-a' flag:\n"
351 mdb_printf("%<b>OPTIONS%</b>\n");
354 " -a Print all of the grouped threads, instead of just a count.\n"
355 " -f Force a re-run of the thread stack gathering.\n"
356 " -v Be verbose about thread stack gathering.\n"
359 mdb_printf("%<b>FILTERS%</b>\n");
362 " -i Show active threads; equivalent to '-S CV'.\n"
363 " -c func[+offset]\n"
364 " Only print threads whose stacks contain func/func+offset.\n"
365 " -C func[+offset]\n"
366 " Only print threads whose stacks do not contain func/func+offset.\n"
368 " Only print threads whose stacks contain functions from module.\n"
370 " Only print threads whose stacks do not contain functions from\n"
373 " Only print threads which are on a 'type' synchronization object\n"
376 " Only print threads which are not on a 'type' SOBJ.\n"
378 " Only print threads which are in thread state 'tstate'.\n"
380 " Only print threads which are not in thread state 'tstate'.\n"