Print this page
patch fix-mdb
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/mdb/common/modules/genunix/findstack.c
+++ new/usr/src/cmd/mdb/common/modules/genunix/findstack.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright (c) 2013, Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
25 25 */
26 26
27 27 #include <mdb/mdb_modapi.h>
28 28 #include <mdb/mdb_ctf.h>
29 29
30 30 #include <sys/types.h>
31 31 #include <sys/regset.h>
32 32 #include <sys/stack.h>
33 33 #include <sys/thread.h>
34 34 #include <sys/modctl.h>
35 35 #include <assert.h>
36 36
37 37 #include "findstack.h"
38 38 #include "thread.h"
39 39 #include "sobj.h"
40 40
41 41 int findstack_debug_on = 0;
42 42
43 43 /*
44 44 * "sp" is a kernel VA.
45 45 */
46 46 static int
47 47 print_stack(uintptr_t sp, uintptr_t pc, uintptr_t addr,
48 48 int argc, const mdb_arg_t *argv, int free_state)
49 49 {
50 50 int showargs = 0, count, err;
51 51
52 52 count = mdb_getopts(argc, argv,
53 53 'v', MDB_OPT_SETBITS, TRUE, &showargs, NULL);
54 54 argc -= count;
55 55 argv += count;
56 56
57 57 if (argc > 1 || (argc == 1 && argv->a_type != MDB_TYPE_STRING))
58 58 return (DCMD_USAGE);
59 59
60 60 mdb_printf("stack pointer for thread %p%s: %p\n",
61 61 addr, (free_state ? " (TS_FREE)" : ""), sp);
62 62 if (pc != 0)
63 63 mdb_printf("[ %0?lr %a() ]\n", sp, pc);
64 64
65 65 mdb_inc_indent(2);
66 66 mdb_set_dot(sp);
67 67
68 68 if (argc == 1)
69 69 err = mdb_eval(argv->a_un.a_str);
70 70 else if (showargs)
71 71 err = mdb_eval("<.$C");
72 72 else
73 73 err = mdb_eval("<.$C0");
74 74
75 75 mdb_dec_indent(2);
76 76
77 77 return ((err == -1) ? DCMD_ABORT : DCMD_OK);
78 78 }
79 79
80 80 int
81 81 findstack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
82 82 {
83 83 findstack_info_t fsi;
84 84 int retval;
85 85
86 86 if (!(flags & DCMD_ADDRSPEC))
87 87 return (DCMD_USAGE);
88 88
89 89 bzero(&fsi, sizeof (fsi));
90 90
91 91 if ((retval = stacks_findstack(addr, &fsi, 1)) != DCMD_OK ||
92 92 fsi.fsi_failed)
93 93 return (retval);
94 94
95 95 return (print_stack(fsi.fsi_sp, fsi.fsi_pc, addr,
96 96 argc, argv, fsi.fsi_tstate == TS_FREE));
97 97 }
98 98
99 99 /*ARGSUSED*/
100 100 int
101 101 findstack_debug(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *av)
102 102 {
103 103 findstack_debug_on ^= 1;
104 104
105 105 mdb_printf("findstack: debugging is now %s\n",
106 106 findstack_debug_on ? "on" : "off");
107 107
108 108 return (DCMD_OK);
109 109 }
110 110
111 111 static void
112 112 uppercase(char *p)
113 113 {
114 114 for (; *p != '\0'; p++) {
115 115 if (*p >= 'a' && *p <= 'z')
116 116 *p += 'A' - 'a';
117 117 }
118 118 }
119 119
120 120 static void
121 121 sobj_to_text(uintptr_t addr, char *out, size_t out_sz)
122 122 {
123 123 sobj_ops_to_text(addr, out, out_sz);
124 124 uppercase(out);
125 125 }
126 126
127 127 #define SOBJ_ALL 1
128 128
129 129 static int
130 130 text_to_sobj(const char *text, uintptr_t *out)
131 131 {
132 132 if (strcasecmp(text, "ALL") == 0) {
133 133 *out = SOBJ_ALL;
134 134 return (0);
135 135 }
136 136
137 137 return (sobj_text_to_ops(text, out));
138 138 }
139 139
140 140 #define TSTATE_PANIC -2U
141 141 static int
142 142 text_to_tstate(const char *text, uint_t *out)
143 143 {
144 144 if (strcasecmp(text, "panic") == 0)
145 145 *out = TSTATE_PANIC;
146 146 else if (thread_text_to_state(text, out) != 0) {
147 147 mdb_warn("tstate \"%s\" not recognized\n", text);
148 148 return (-1);
149 149 }
150 150 return (0);
151 151 }
152 152
153 153 static void
154 154 tstate_to_text(uint_t tstate, uint_t paniced, char *out, size_t out_sz)
155 155 {
156 156 if (paniced)
157 157 mdb_snprintf(out, out_sz, "panic");
158 158 else
159 159 thread_state_to_text(tstate, out, out_sz);
160 160 uppercase(out);
161 161 }
162 162
163 163 typedef struct stacks_entry {
164 164 struct stacks_entry *se_next;
165 165 struct stacks_entry *se_dup; /* dups of this stack */
166 166 uintptr_t se_thread;
167 167 uintptr_t se_sp;
168 168 uintptr_t se_sobj_ops;
169 169 uint32_t se_tstate;
170 170 uint32_t se_count; /* # threads w/ this stack */
171 171 uint8_t se_overflow;
172 172 uint8_t se_depth;
173 173 uint8_t se_failed; /* failure reason; FSI_FAIL_* */
174 174 uint8_t se_panic;
175 175 uintptr_t se_stack[1];
176 176 } stacks_entry_t;
177 177 #define STACKS_ENTRY_SIZE(x) OFFSETOF(stacks_entry_t, se_stack[(x)])
178 178
179 179 #define STACKS_HSIZE 127
180 180
181 181 /* Maximum stack depth reported in stacks */
182 182 #define STACKS_MAX_DEPTH 254
183 183
184 184 typedef struct stacks_info {
185 185 size_t si_count; /* total stacks_entry_ts (incl dups) */
186 186 size_t si_entries; /* # entries in hash table */
187 187 stacks_entry_t **si_hash; /* hash table */
188 188 findstack_info_t si_fsi; /* transient callback state */
189 189 } stacks_info_t;
190 190
191 191 /* global state cached between invocations */
192 192 #define STACKS_STATE_CLEAN 0
193 193 #define STACKS_STATE_DIRTY 1
194 194 #define STACKS_STATE_DONE 2
195 195 static uint_t stacks_state = STACKS_STATE_CLEAN;
196 196 static stacks_entry_t **stacks_hash;
197 197 static stacks_entry_t **stacks_array;
198 198 static size_t stacks_array_size;
199 199
200 200 size_t
201 201 stacks_hash_entry(stacks_entry_t *sep)
202 202 {
203 203 size_t depth = sep->se_depth;
204 204 uintptr_t *stack = sep->se_stack;
205 205
206 206 uint64_t total = depth;
207 207
208 208 while (depth > 0) {
209 209 total += *stack;
210 210 stack++; depth--;
211 211 }
212 212
213 213 return (total % STACKS_HSIZE);
214 214 }
215 215
216 216 /*
217 217 * This is used to both compare stacks for equality and to sort the final
218 218 * list of unique stacks. forsort specifies the latter behavior, which
219 219 * additionally:
220 220 * compares se_count, and
221 221 * sorts the stacks by text function name.
222 222 *
223 223 * The equality test is independent of se_count, and doesn't care about
224 224 * relative ordering, so we don't do the extra work of looking up symbols
225 225 * for the stack addresses.
226 226 */
227 227 int
228 228 stacks_entry_comp_impl(stacks_entry_t *l, stacks_entry_t *r,
229 229 uint_t forsort)
230 230 {
231 231 int idx;
232 232
233 233 int depth = MIN(l->se_depth, r->se_depth);
234 234
235 235 /* no matter what, panic stacks come last. */
236 236 if (l->se_panic > r->se_panic)
237 237 return (1);
238 238 if (l->se_panic < r->se_panic)
239 239 return (-1);
240 240
241 241 if (forsort) {
242 242 /* put large counts earlier */
243 243 if (l->se_count > r->se_count)
244 244 return (-1);
245 245 if (l->se_count < r->se_count)
246 246 return (1);
247 247 }
248 248
249 249 if (l->se_tstate > r->se_tstate)
250 250 return (1);
251 251 if (l->se_tstate < r->se_tstate)
252 252 return (-1);
253 253
254 254 if (l->se_failed > r->se_failed)
255 255 return (1);
256 256 if (l->se_failed < r->se_failed)
257 257 return (-1);
258 258
259 259 for (idx = 0; idx < depth; idx++) {
260 260 char lbuf[MDB_SYM_NAMLEN];
261 261 char rbuf[MDB_SYM_NAMLEN];
262 262
263 263 int rval;
264 264 uintptr_t laddr = l->se_stack[idx];
265 265 uintptr_t raddr = r->se_stack[idx];
266 266
267 267 if (laddr == raddr)
268 268 continue;
269 269
270 270 if (forsort &&
271 271 mdb_lookup_by_addr(laddr, MDB_SYM_FUZZY,
272 272 lbuf, sizeof (lbuf), NULL) != -1 &&
273 273 mdb_lookup_by_addr(raddr, MDB_SYM_FUZZY,
274 274 rbuf, sizeof (rbuf), NULL) != -1 &&
275 275 (rval = strcmp(lbuf, rbuf)) != 0)
276 276 return (rval);
277 277
278 278 if (laddr > raddr)
279 279 return (1);
280 280 return (-1);
281 281 }
282 282
283 283 if (l->se_overflow > r->se_overflow)
284 284 return (-1);
285 285 if (l->se_overflow < r->se_overflow)
286 286 return (1);
287 287
288 288 if (l->se_depth > r->se_depth)
289 289 return (1);
290 290 if (l->se_depth < r->se_depth)
291 291 return (-1);
292 292
293 293 if (l->se_sobj_ops > r->se_sobj_ops)
294 294 return (1);
295 295 if (l->se_sobj_ops < r->se_sobj_ops)
296 296 return (-1);
297 297
298 298 return (0);
299 299 }
300 300
301 301 int
302 302 stacks_entry_comp(const void *l_arg, const void *r_arg)
303 303 {
304 304 stacks_entry_t * const *lp = l_arg;
305 305 stacks_entry_t * const *rp = r_arg;
306 306
307 307 return (stacks_entry_comp_impl(*lp, *rp, 1));
308 308 }
309 309
310 310 void
311 311 stacks_cleanup(int force)
312 312 {
313 313 int idx = 0;
314 314 stacks_entry_t *cur, *next;
315 315
316 316 if (stacks_state == STACKS_STATE_CLEAN)
317 317 return;
318 318
319 319 if (!force && stacks_state == STACKS_STATE_DONE)
320 320 return;
321 321
322 322 /*
323 323 * Until the array is sorted and stable, stacks_hash will be non-NULL.
324 324 * This way, we can get at all of the data, even if qsort() was
325 325 * interrupted while mucking with the array.
326 326 */
327 327 if (stacks_hash != NULL) {
328 328 for (idx = 0; idx < STACKS_HSIZE; idx++) {
329 329 while ((cur = stacks_hash[idx]) != NULL) {
330 330 while ((next = cur->se_dup) != NULL) {
331 331 cur->se_dup = next->se_dup;
332 332 mdb_free(next,
333 333 STACKS_ENTRY_SIZE(next->se_depth));
334 334 }
335 335 next = cur->se_next;
336 336 stacks_hash[idx] = next;
337 337 mdb_free(cur, STACKS_ENTRY_SIZE(cur->se_depth));
338 338 }
339 339 }
340 340 if (stacks_array != NULL)
341 341 mdb_free(stacks_array,
342 342 stacks_array_size * sizeof (*stacks_array));
343 343
344 344 mdb_free(stacks_hash, STACKS_HSIZE * sizeof (*stacks_hash));
345 345
346 346 } else if (stacks_array != NULL) {
347 347 for (idx = 0; idx < stacks_array_size; idx++) {
348 348 if ((cur = stacks_array[idx]) != NULL) {
349 349 while ((next = cur->se_dup) != NULL) {
350 350 cur->se_dup = next->se_dup;
351 351 mdb_free(next,
352 352 STACKS_ENTRY_SIZE(next->se_depth));
353 353 }
354 354 stacks_array[idx] = NULL;
355 355 mdb_free(cur, STACKS_ENTRY_SIZE(cur->se_depth));
356 356 }
357 357 }
358 358 mdb_free(stacks_array,
359 359 stacks_array_size * sizeof (*stacks_array));
360 360 }
361 361
362 362 stacks_findstack_cleanup();
363 363
364 364 stacks_array_size = 0;
365 365 stacks_state = STACKS_STATE_CLEAN;
366 366 stacks_hash = NULL;
367 367 stacks_array = NULL;
368 368 }
369 369
370 370 /*ARGSUSED*/
371 371 int
372 372 stacks_thread_cb(uintptr_t addr, const void *ignored, void *cbarg)
373 373 {
374 374 stacks_info_t *sip = cbarg;
375 375 findstack_info_t *fsip = &sip->si_fsi;
376 376
377 377 stacks_entry_t **sepp, *nsep, *sep;
378 378 int idx;
379 379 size_t depth;
380 380
381 381 if (stacks_findstack(addr, fsip, 0) != DCMD_OK &&
382 382 fsip->fsi_failed == FSI_FAIL_BADTHREAD) {
383 383 mdb_warn("couldn't read thread at %p\n", addr);
384 384 return (WALK_NEXT);
385 385 }
386 386
387 387 sip->si_count++;
388 388
389 389 depth = fsip->fsi_depth;
390 390 nsep = mdb_zalloc(STACKS_ENTRY_SIZE(depth), UM_SLEEP);
391 391 nsep->se_thread = addr;
392 392 nsep->se_sp = fsip->fsi_sp;
393 393 nsep->se_sobj_ops = fsip->fsi_sobj_ops;
394 394 nsep->se_tstate = fsip->fsi_tstate;
395 395 nsep->se_count = 1;
396 396 nsep->se_overflow = fsip->fsi_overflow;
397 397 nsep->se_depth = depth;
398 398 nsep->se_failed = fsip->fsi_failed;
399 399 nsep->se_panic = fsip->fsi_panic;
400 400
401 401 for (idx = 0; idx < depth; idx++)
402 402 nsep->se_stack[idx] = fsip->fsi_stack[idx];
403 403
404 404 for (sepp = &sip->si_hash[stacks_hash_entry(nsep)];
405 405 (sep = *sepp) != NULL;
406 406 sepp = &sep->se_next) {
407 407
408 408 if (stacks_entry_comp_impl(sep, nsep, 0) != 0)
409 409 continue;
410 410
411 411 nsep->se_dup = sep->se_dup;
412 412 sep->se_dup = nsep;
413 413 sep->se_count++;
414 414 return (WALK_NEXT);
415 415 }
416 416
417 417 nsep->se_next = NULL;
418 418 *sepp = nsep;
419 419 sip->si_entries++;
420 420
421 421 return (WALK_NEXT);
422 422 }
423 423
424 424 int
425 425 stacks_run_tlist(mdb_pipe_t *tlist, stacks_info_t *si)
426 426 {
427 427 size_t idx;
428 428 size_t found = 0;
429 429 int ret;
430 430
431 431 for (idx = 0; idx < tlist->pipe_len; idx++) {
432 432 uintptr_t addr = tlist->pipe_data[idx];
433 433
434 434 found++;
435 435
436 436 ret = stacks_thread_cb(addr, NULL, si);
437 437 if (ret == WALK_DONE)
438 438 break;
439 439 if (ret != WALK_NEXT)
440 440 return (-1);
441 441 }
442 442
443 443 if (found)
444 444 return (0);
445 445 return (-1);
446 446 }
447 447
448 448 int
449 449 stacks_run(int verbose, mdb_pipe_t *tlist)
450 450 {
451 451 stacks_info_t si;
452 452 findstack_info_t *fsip = &si.si_fsi;
453 453 size_t idx;
454 454 stacks_entry_t **cur;
455 455
456 456 bzero(&si, sizeof (si));
457 457
458 458 stacks_state = STACKS_STATE_DIRTY;
459 459
460 460 stacks_hash = si.si_hash =
461 461 mdb_zalloc(STACKS_HSIZE * sizeof (*si.si_hash), UM_SLEEP);
462 462 si.si_entries = 0;
463 463 si.si_count = 0;
464 464
465 465 fsip->fsi_max_depth = STACKS_MAX_DEPTH;
466 466 fsip->fsi_stack =
467 467 mdb_alloc(fsip->fsi_max_depth * sizeof (*fsip->fsi_stack),
468 468 UM_SLEEP | UM_GC);
469 469
470 470 if (verbose)
471 471 mdb_warn("stacks: processing kernel threads\n");
472 472
473 473 if (tlist != NULL) {
474 474 if (stacks_run_tlist(tlist, &si))
475 475 return (DCMD_ERR);
476 476 } else {
477 477 if (mdb_walk("thread", stacks_thread_cb, &si) != 0) {
478 478 mdb_warn("cannot walk \"thread\"");
479 479 return (DCMD_ERR);
480 480 }
481 481 }
482 482
483 483 if (verbose)
484 484 mdb_warn("stacks: %d unique stacks / %d threads\n",
485 485 si.si_entries, si.si_count);
486 486
487 487 stacks_array_size = si.si_entries;
488 488 stacks_array =
489 489 mdb_zalloc(si.si_entries * sizeof (*stacks_array), UM_SLEEP);
490 490 cur = stacks_array;
491 491 for (idx = 0; idx < STACKS_HSIZE; idx++) {
492 492 stacks_entry_t *sep;
493 493 for (sep = si.si_hash[idx]; sep != NULL; sep = sep->se_next)
494 494 *(cur++) = sep;
495 495 }
496 496
497 497 if (cur != stacks_array + si.si_entries) {
498 498 mdb_warn("stacks: miscounted array size (%d != size: %d)\n",
499 499 (cur - stacks_array), stacks_array_size);
500 500 return (DCMD_ERR);
501 501 }
502 502 qsort(stacks_array, si.si_entries, sizeof (*stacks_array),
503 503 stacks_entry_comp);
504 504
505 505 /* Now that we're done, free the hash table */
506 506 stacks_hash = NULL;
507 507 mdb_free(si.si_hash, STACKS_HSIZE * sizeof (*si.si_hash));
508 508
509 509 if (tlist == NULL)
510 510 stacks_state = STACKS_STATE_DONE;
511 511
512 512 if (verbose)
513 513 mdb_warn("stacks: done\n");
514 514
515 515 return (DCMD_OK);
516 516 }
517 517
518 518 static int
519 519 stacks_has_caller(stacks_entry_t *sep, uintptr_t addr)
520 520 {
521 521 uintptr_t laddr = addr;
522 522 uintptr_t haddr = addr + 1;
523 523 int idx;
524 524 char c[MDB_SYM_NAMLEN];
525 525 GElf_Sym sym;
526 526
527 527 if (mdb_lookup_by_addr(addr, MDB_SYM_FUZZY,
528 528 c, sizeof (c), &sym) != -1 &&
529 529 addr == (uintptr_t)sym.st_value) {
530 530 laddr = (uintptr_t)sym.st_value;
531 531 haddr = (uintptr_t)sym.st_value + sym.st_size;
532 532 }
533 533
534 534 for (idx = 0; idx < sep->se_depth; idx++)
535 535 if (sep->se_stack[idx] >= laddr && sep->se_stack[idx] < haddr)
536 536 return (1);
537 537
538 538 return (0);
539 539 }
540 540
541 541 static int
542 542 stacks_has_module(stacks_entry_t *sep, stacks_module_t *mp)
543 543 {
544 544 int idx;
545 545
546 546 for (idx = 0; idx < sep->se_depth; idx++) {
547 547 if (sep->se_stack[idx] >= mp->sm_text &&
548 548 sep->se_stack[idx] < mp->sm_text + mp->sm_size)
549 549 return (1);
550 550 }
551 551
552 552 return (0);
553 553 }
554 554
555 555 static int
556 556 stacks_module_find(const char *name, stacks_module_t *mp)
557 557 {
558 558 (void) strncpy(mp->sm_name, name, sizeof (mp->sm_name));
559 559
560 560 if (stacks_module(mp) != 0)
561 561 return (-1);
562 562
563 563 if (mp->sm_size == 0) {
564 564 mdb_warn("stacks: module \"%s\" is unknown\n", name);
565 565 return (-1);
566 566 }
567 567
568 568 return (0);
569 569 }
570 570
571 571 static int
572 572 uintptrcomp(const void *lp, const void *rp)
573 573 {
574 574 uintptr_t lhs = *(const uintptr_t *)lp;
575 575 uintptr_t rhs = *(const uintptr_t *)rp;
576 576 if (lhs > rhs)
577 577 return (1);
578 578 if (lhs < rhs)
579 579 return (-1);
580 580 return (0);
581 581 }
582 582
583 583 /*ARGSUSED*/
584 584 int
585 585 stacks(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
586 586 {
587 587 size_t idx;
588 588
589 589 char *seen = NULL;
590 590
591 591 const char *caller_str = NULL;
592 592 const char *excl_caller_str = NULL;
593 593 uintptr_t caller = 0, excl_caller = 0;
594 594 const char *module_str = NULL;
595 595 const char *excl_module_str = NULL;
596 596 stacks_module_t module, excl_module;
597 597 const char *sobj = NULL;
598 598 const char *excl_sobj = NULL;
599 599 uintptr_t sobj_ops = 0, excl_sobj_ops = 0;
600 600 const char *tstate_str = NULL;
601 601 const char *excl_tstate_str = NULL;
602 602 uint_t tstate = -1U;
603 603 uint_t excl_tstate = -1U;
604 604 uint_t printed = 0;
605 605
606 606 uint_t all = 0;
607 607 uint_t force = 0;
608 608 uint_t interesting = 0;
609 609 uint_t verbose = 0;
610 610
611 611 /*
612 612 * We have a slight behavior difference between having piped
613 613 * input and 'addr::stacks'. Without a pipe, we assume the
614 614 * thread pointer given is a representative thread, and so
615 615 * we include all similar threads in the system in our output.
616 616 *
617 617 * With a pipe, we filter down to just the threads in our
618 618 * input.
619 619 */
620 620 uint_t addrspec = (flags & DCMD_ADDRSPEC);
621 621 uint_t only_matching = addrspec && (flags & DCMD_PIPE);
622 622
623 623 mdb_pipe_t p;
624 624
625 625 bzero(&module, sizeof (module));
626 626 bzero(&excl_module, sizeof (excl_module));
627 627
628 628 if (mdb_getopts(argc, argv,
629 629 'a', MDB_OPT_SETBITS, TRUE, &all,
630 630 'f', MDB_OPT_SETBITS, TRUE, &force,
631 631 'i', MDB_OPT_SETBITS, TRUE, &interesting,
632 632 'v', MDB_OPT_SETBITS, TRUE, &verbose,
633 633 'c', MDB_OPT_STR, &caller_str,
634 634 'C', MDB_OPT_STR, &excl_caller_str,
635 635 'm', MDB_OPT_STR, &module_str,
636 636 'M', MDB_OPT_STR, &excl_module_str,
637 637 's', MDB_OPT_STR, &sobj,
638 638 'S', MDB_OPT_STR, &excl_sobj,
639 639 't', MDB_OPT_STR, &tstate_str,
640 640 'T', MDB_OPT_STR, &excl_tstate_str,
641 641 NULL) != argc)
642 642 return (DCMD_USAGE);
643 643
644 644 if (interesting) {
645 645 if (sobj != NULL || excl_sobj != NULL ||
646 646 tstate_str != NULL || excl_tstate_str != NULL) {
647 647 mdb_warn(
648 648 "stacks: -i is incompatible with -[sStT]\n");
649 649 return (DCMD_USAGE);
650 650 }
651 651 excl_sobj = "CV";
652 652 excl_tstate_str = "FREE";
653 653 }
654 654
655 655 if (caller_str != NULL) {
656 656 mdb_set_dot(0);
657 657 if (mdb_eval(caller_str) != 0) {
658 658 mdb_warn("stacks: evaluation of \"%s\" failed",
659 659 caller_str);
660 660 return (DCMD_ABORT);
661 661 }
662 662 caller = mdb_get_dot();
663 663 }
664 664
665 665 if (excl_caller_str != NULL) {
666 666 mdb_set_dot(0);
667 667 if (mdb_eval(excl_caller_str) != 0) {
668 668 mdb_warn("stacks: evaluation of \"%s\" failed",
669 669 excl_caller_str);
670 670 return (DCMD_ABORT);
671 671 }
672 672 excl_caller = mdb_get_dot();
673 673 }
674 674 mdb_set_dot(addr);
675 675
676 676 if (module_str != NULL && stacks_module_find(module_str, &module) != 0)
677 677 return (DCMD_ABORT);
678 678
679 679 if (excl_module_str != NULL &&
680 680 stacks_module_find(excl_module_str, &excl_module) != 0)
681 681 return (DCMD_ABORT);
682 682
683 683 if (sobj != NULL && text_to_sobj(sobj, &sobj_ops) != 0)
684 684 return (DCMD_USAGE);
685 685
686 686 if (excl_sobj != NULL && text_to_sobj(excl_sobj, &excl_sobj_ops) != 0)
687 687 return (DCMD_USAGE);
688 688
689 689 if (sobj_ops != 0 && excl_sobj_ops != 0) {
690 690 mdb_warn("stacks: only one of -s and -S can be specified\n");
691 691 return (DCMD_USAGE);
692 692 }
693 693
694 694 if (tstate_str != NULL && text_to_tstate(tstate_str, &tstate) != 0)
695 695 return (DCMD_USAGE);
696 696
697 697 if (excl_tstate_str != NULL &&
698 698 text_to_tstate(excl_tstate_str, &excl_tstate) != 0)
699 699 return (DCMD_USAGE);
700 700
701 701 if (tstate != -1U && excl_tstate != -1U) {
702 702 mdb_warn("stacks: only one of -t and -T can be specified\n");
703 703 return (DCMD_USAGE);
704 704 }
705 705
706 706 /*
707 707 * If there's an address specified, we're going to further filter
708 708 * to only entries which have an address in the input. To reduce
709 709 * overhead (and make the sorted output come out right), we
710 710 * use mdb_get_pipe() to grab the entire pipeline of input, then
711 711 * use qsort() and bsearch() to speed up the search.
712 712 */
713 713 if (addrspec) {
714 714 mdb_get_pipe(&p);
715 715 if (p.pipe_data == NULL || p.pipe_len == 0) {
716 716 p.pipe_data = &addr;
717 717 p.pipe_len = 1;
718 718 }
719 719 qsort(p.pipe_data, p.pipe_len, sizeof (uintptr_t),
720 720 uintptrcomp);
721 721
722 722 /* remove any duplicates in the data */
723 723 idx = 0;
724 724 while (idx < p.pipe_len - 1) {
725 725 uintptr_t *data = &p.pipe_data[idx];
726 726 size_t len = p.pipe_len - idx;
727 727
728 728 if (data[0] == data[1]) {
729 729 memmove(data, data + 1,
730 730 (len - 1) * sizeof (*data));
731 731 p.pipe_len--;
732 732 continue; /* repeat without incrementing idx */
733 733 }
734 734 idx++;
735 735 }
736 736
737 737 seen = mdb_zalloc(p.pipe_len, UM_SLEEP | UM_GC);
738 738 }
739 739
740 740 /*
741 741 * Force a cleanup if we're connected to a live system. Never
742 742 * do a cleanup after the first invocation around the loop.
743 743 */
744 744 force |= (mdb_get_state() == MDB_STATE_RUNNING);
745 745 if (force && (flags & (DCMD_LOOPFIRST|DCMD_LOOP)) == DCMD_LOOP)
746 746 force = 0;
747 747
748 748 stacks_cleanup(force);
749 749
750 750 if (stacks_state == STACKS_STATE_CLEAN) {
751 751 int res = stacks_run(verbose, addrspec ? &p : NULL);
752 752 if (res != DCMD_OK)
753 753 return (res);
754 754 }
755 755
756 756 for (idx = 0; idx < stacks_array_size; idx++) {
757 757 stacks_entry_t *sep = stacks_array[idx];
758 758 stacks_entry_t *cur = sep;
759 759 int frame;
760 760 size_t count = sep->se_count;
761 761
762 762 if (addrspec) {
763 763 stacks_entry_t *head = NULL, *tail = NULL, *sp;
764 764 size_t foundcount = 0;
765 765 /*
766 766 * We use the now-unused hash chain field se_next to
767 767 * link together the dups which match our list.
768 768 */
769 769 for (sp = sep; sp != NULL; sp = sp->se_dup) {
770 770 uintptr_t *entry = bsearch(&sp->se_thread,
771 771 p.pipe_data, p.pipe_len, sizeof (uintptr_t),
772 772 uintptrcomp);
773 773 if (entry != NULL) {
774 774 foundcount++;
775 775 seen[entry - p.pipe_data]++;
776 776 if (head == NULL)
777 777 head = sp;
778 778 else
779 779 tail->se_next = sp;
780 780 tail = sp;
781 781 sp->se_next = NULL;
782 782 }
783 783 }
784 784 if (head == NULL)
785 785 continue; /* no match, skip entry */
786 786
787 787 if (only_matching) {
788 788 cur = sep = head;
789 789 count = foundcount;
790 790 }
791 791 }
792 792
793 793 if (caller != 0 && !stacks_has_caller(sep, caller))
794 794 continue;
795 795
796 796 if (excl_caller != 0 && stacks_has_caller(sep, excl_caller))
797 797 continue;
798 798
799 799 if (module.sm_size != 0 && !stacks_has_module(sep, &module))
800 800 continue;
801 801
802 802 if (excl_module.sm_size != 0 &&
803 803 stacks_has_module(sep, &excl_module))
804 804 continue;
805 805
806 806 if (tstate != -1U) {
807 807 if (tstate == TSTATE_PANIC) {
808 808 if (!sep->se_panic)
809 809 continue;
810 810 } else if (sep->se_panic || sep->se_tstate != tstate)
811 811 continue;
812 812 }
813 813 if (excl_tstate != -1U) {
814 814 if (excl_tstate == TSTATE_PANIC) {
815 815 if (sep->se_panic)
816 816 continue;
817 817 } else if (!sep->se_panic &&
818 818 sep->se_tstate == excl_tstate)
819 819 continue;
820 820 }
821 821
822 822 if (sobj_ops == SOBJ_ALL) {
823 823 if (sep->se_sobj_ops == 0)
824 824 continue;
825 825 } else if (sobj_ops != 0) {
826 826 if (sobj_ops != sep->se_sobj_ops)
827 827 continue;
828 828 }
829 829
830 830 if (!(interesting && sep->se_panic)) {
831 831 if (excl_sobj_ops == SOBJ_ALL) {
832 832 if (sep->se_sobj_ops != 0)
833 833 continue;
834 834 } else if (excl_sobj_ops != 0) {
835 835 if (excl_sobj_ops == sep->se_sobj_ops)
836 836 continue;
837 837 }
838 838 }
839 839
840 840 if (flags & DCMD_PIPE_OUT) {
841 841 while (sep != NULL) {
842 842 mdb_printf("%lr\n", sep->se_thread);
843 843 sep = only_matching ?
844 844 sep->se_next : sep->se_dup;
845 845 }
846 846 continue;
847 847 }
848 848
849 849 if (all || !printed) {
850 850 mdb_printf("%<u>%-?s %-8s %-?s %8s%</u>\n",
851 851 "THREAD", "STATE", "SOBJ", "COUNT");
852 852 printed = 1;
853 853 }
854 854
855 855 do {
856 856 char state[20];
857 857 char sobj[100];
858 858
859 859 tstate_to_text(cur->se_tstate, cur->se_panic,
860 860 state, sizeof (state));
861 861 sobj_to_text(cur->se_sobj_ops,
862 862 sobj, sizeof (sobj));
863 863
864 864 if (cur == sep)
865 865 mdb_printf("%-?p %-8s %-?s %8d\n",
866 866 cur->se_thread, state, sobj, count);
↓ open down ↓ |
866 lines elided |
↑ open up ↑ |
867 867 else
868 868 mdb_printf("%-?p %-8s %-?s %8s\n",
869 869 cur->se_thread, state, sobj, "-");
870 870
871 871 cur = only_matching ? cur->se_next : cur->se_dup;
872 872 } while (all && cur != NULL);
873 873
874 874 if (sep->se_failed != 0) {
875 875 char *reason;
876 876 switch (sep->se_failed) {
877 - case FSI_FAIL_NOTINMEMORY:
878 - reason = "thread not in memory";
879 - break;
880 877 case FSI_FAIL_THREADCORRUPT:
881 878 reason = "thread structure stack info corrupt";
882 879 break;
883 880 case FSI_FAIL_STACKNOTFOUND:
884 881 reason = "no consistent stack found";
885 882 break;
886 883 default:
887 884 reason = "unknown failure";
888 885 break;
889 886 }
890 887 mdb_printf("%?s <%s>\n", "", reason);
891 888 }
892 889
893 890 for (frame = 0; frame < sep->se_depth; frame++)
894 891 mdb_printf("%?s %a\n", "", sep->se_stack[frame]);
895 892 if (sep->se_overflow)
896 893 mdb_printf("%?s ... truncated ...\n", "");
897 894 mdb_printf("\n");
898 895 }
899 896
900 897 if (flags & DCMD_ADDRSPEC) {
901 898 for (idx = 0; idx < p.pipe_len; idx++)
902 899 if (seen[idx] == 0)
903 900 mdb_warn("stacks: %p not in thread list\n",
904 901 p.pipe_data[idx]);
905 902 }
906 903 return (DCMD_OK);
907 904 }
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX