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
== (uintptr_t)NULL
?
109 "<none>" : (char *)addr
);
113 stacks_module_callback(mdb_object_t
*obj
, void *arg
)
115 stacks_module_t
*smp
= arg
;
116 boolean_t match
= (strcmp(obj
->obj_name
, smp
->sm_name
) == 0);
117 char *suffix
= ".so";
118 const char *s
, *next
;
121 if (smp
->sm_size
!= 0)
125 * It doesn't match the name, but -- for convenience -- we want to
126 * allow matches before ".so.[suffix]". An aside: why doesn't
127 * strrstr() exist? (Don't google that. I'm serious, don't do it.
128 * If you do, and you read the thread of "why doesn't strrstr() exist?"
129 * circa 2005 you will see things that you will NEVER be able to unsee!)
131 if (!match
&& (s
= strstr(obj
->obj_name
, suffix
)) != NULL
) {
132 while ((next
= strstr(s
+ 1, suffix
)) != NULL
) {
137 len
= s
- obj
->obj_name
;
139 match
= (strncmp(smp
->sm_name
, obj
->obj_name
, len
) == 0 &&
140 smp
->sm_name
[len
] == '\0');
144 * If we have a library that has the libc directory in the path, we
145 * want to match against anything that would match libc.so.1. (This
146 * is necessary to be able to easily deal with libc implementations
147 * that have alternate hardware capabilities.)
149 if (!match
&& strstr(obj
->obj_fullname
, "/libc/") != NULL
) {
150 mdb_object_t libc
= *obj
;
152 libc
.obj_name
= "libc.so.1";
153 libc
.obj_fullname
= "";
155 return (stacks_module_callback(&libc
, arg
));
159 smp
->sm_text
= obj
->obj_base
;
160 smp
->sm_size
= obj
->obj_size
;
167 stacks_module(stacks_module_t
*smp
)
169 if (mdb_object_iter(stacks_module_callback
, smp
) != 0)
175 typedef struct stacks_ulwp
{
176 avl_node_t sulwp_node
;
178 uintptr_t sulwp_addr
;
181 boolean_t stacks_ulwp_initialized
;
182 avl_tree_t stacks_ulwp_byid
;
186 stacks_ulwp_walk(uintptr_t addr
, ulwp_t
*ulwp
, void *ignored
)
188 stacks_ulwp_t
*sulwp
= mdb_alloc(sizeof (stacks_ulwp_t
), UM_SLEEP
);
190 sulwp
->sulwp_id
= ulwp
->ul_lwpid
;
191 sulwp
->sulwp_addr
= addr
;
193 if (avl_find(&stacks_ulwp_byid
, sulwp
, NULL
) != NULL
) {
194 mdb_warn("found multiple LWPs with ID %d!", ulwp
->ul_lwpid
);
198 avl_add(&stacks_ulwp_byid
, sulwp
);
204 stacks_ulwp_compare(const void *l
, const void *r
)
206 const stacks_ulwp_t
*lhs
= l
;
207 const stacks_ulwp_t
*rhs
= r
;
209 if (lhs
->sulwp_id
> rhs
->sulwp_id
)
212 if (lhs
->sulwp_id
< rhs
->sulwp_id
)
220 stacks_findstack(uintptr_t addr
, findstack_info_t
*fsip
, uint_t print_warnings
)
224 struct rwindow frame
;
225 avl_tree_t
*tree
= &stacks_ulwp_byid
;
226 stacks_ulwp_t
*sulwp
, cmp
;
229 fsip
->fsi_failed
= 0;
233 fsip
->fsi_overflow
= 0;
235 if (!stacks_ulwp_initialized
) {
236 avl_create(tree
, stacks_ulwp_compare
, sizeof (stacks_ulwp_t
),
237 offsetof(stacks_ulwp_t
, sulwp_node
));
240 (mdb_walk_cb_t
)stacks_ulwp_walk
, NULL
) != 0) {
241 mdb_warn("couldn't walk 'ulwp'");
245 stacks_ulwp_initialized
= B_TRUE
;
248 bzero(&cmp
, sizeof (cmp
));
249 cmp
.sulwp_id
= (lwpid_t
)addr
;
251 if ((sulwp
= avl_find(tree
, &cmp
, NULL
)) == NULL
) {
252 mdb_warn("couldn't find ulwp_t for tid %d\n", cmp
.sulwp_id
);
256 if (mdb_vread(&ulwp
, sizeof (ulwp
), sulwp
->sulwp_addr
) == -1) {
257 mdb_warn("couldn't read ulwp_t for tid %d at %p",
258 cmp
.sulwp_id
, sulwp
->sulwp_addr
);
262 fsip
->fsi_tstate
= ulwp
.ul_sleepq
!= NULL
;
263 fsip
->fsi_sobj_ops
= (uintptr_t)(ulwp
.ul_sleepq
== NULL
?
265 (ulwp
.ul_qtype
== MX
? STACKS_SOBJ_MX
: STACKS_SOBJ_CV
));
267 if (mdb_getareg(addr
, STACKS_REGS_FP
, ®
) != 0) {
268 mdb_warn("couldn't read frame pointer for thread 0x%p", addr
);
272 fsip
->fsi_sp
= fp
= (uintptr_t)reg
;
275 if (mdb_getareg(addr
, STACKS_REGS_RC
, ®
) != 0) {
276 mdb_warn("couldn't read program counter for thread 0x%p", addr
);
280 fsip
->fsi_pc
= (uintptr_t)reg
;
283 while (fp
!= (uintptr_t)NULL
) {
284 if (mdb_vread(&frame
, sizeof (frame
), fp
) == -1) {
285 mdb_warn("couldn't read frame for thread 0x%p at %p",
290 if (frame
.rw_rtn
== (uintptr_t)NULL
)
293 if (fsip
->fsi_depth
< fsip
->fsi_max_depth
) {
294 fsip
->fsi_stack
[fsip
->fsi_depth
++] = frame
.rw_rtn
;
296 fsip
->fsi_overflow
= 1;
300 fp
= frame
.rw_fp
+ STACK_BIAS
;
307 stacks_findstack_cleanup()
309 avl_tree_t
*tree
= &stacks_ulwp_byid
;
311 stacks_ulwp_t
*sulwp
;
313 if (!stacks_ulwp_initialized
)
316 while ((sulwp
= avl_destroy_nodes(tree
, &cookie
)) != NULL
)
317 mdb_free(sulwp
, sizeof (stacks_ulwp_t
));
319 bzero(tree
, sizeof (*tree
));
320 stacks_ulwp_initialized
= B_FALSE
;
327 "::stacks processes all of the thread stacks in the process, grouping\n"
328 "together threads which have the same:\n"
331 " * Sync object type, and\n"
332 " * PCs in their stack trace.\n"
334 "The default output (no address or options) is just a dump of the thread\n"
335 "groups in the process. For a view of active threads, use \"::stacks -i\",\n"
336 "which filters out threads sleeping on a CV. More general filtering options\n"
337 "are described below, in the \"FILTERS\" section.\n"
339 "::stacks can be used in a pipeline. The input to ::stacks is one or more\n"
340 "thread IDs. When output into a pipe, ::stacks prints all of the threads \n"
341 "input, filtered by the given filtering options. This means that multiple\n"
342 "::stacks invocations can be piped together to achieve more complicated\n"
343 "filters. For example, to get threads which have both '__door_return' and\n"
344 "'mutex_lock' in their stack trace, you could do:\n"
346 " ::stacks -c __door_return | ::stacks -c mutex_lock\n"
348 "To get the full list of threads in each group, use the '-a' flag:\n"
353 mdb_printf("%<b>OPTIONS%</b>\n");
356 " -a Print all of the grouped threads, instead of just a count.\n"
357 " -f Force a re-run of the thread stack gathering.\n"
358 " -v Be verbose about thread stack gathering.\n"
361 mdb_printf("%<b>FILTERS%</b>\n");
364 " -i Show active threads; equivalent to '-S CV'.\n"
365 " -c func[+offset]\n"
366 " Only print threads whose stacks contain func/func+offset.\n"
367 " -C func[+offset]\n"
368 " Only print threads whose stacks do not contain func/func+offset.\n"
370 " Only print threads whose stacks contain functions from module.\n"
372 " Only print threads whose stacks do not contain functions from\n"
375 " Only print threads which are on a 'type' synchronization object\n"
378 " Only print threads which are not on a 'type' SOBJ.\n"
380 " Only print threads which are in thread state 'tstate'.\n"
382 " Only print threads which are not in thread state 'tstate'.\n"