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