Print this page
8158 Want named threads API
9857 proc manpages should have LIBRARY section
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/mdb/common/modules/genunix/thread.c
+++ new/usr/src/cmd/mdb/common/modules/genunix/thread.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
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25 /*
26 26 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
27 + * Copyright (c) 2018, Joyent, Inc.
27 28 */
28 29
29 30
30 31 #include <mdb/mdb_modapi.h>
31 32 #include <mdb/mdb_ks.h>
33 +#include <mdb/mdb_ctf.h>
32 34 #include <sys/types.h>
33 35 #include <sys/thread.h>
34 36 #include <sys/lwp.h>
35 37 #include <sys/proc.h>
36 38 #include <sys/cpuvar.h>
37 39 #include <sys/cpupart.h>
38 40 #include <sys/disp.h>
39 41 #include <sys/taskq_impl.h>
40 42 #include <sys/stack.h>
43 +#include "thread.h"
41 44
42 45 #ifndef STACK_BIAS
43 46 #define STACK_BIAS 0
44 47 #endif
45 48
46 49 typedef struct thread_walk {
47 50 kthread_t *tw_thread;
48 51 uintptr_t tw_last;
49 52 uint_t tw_inproc;
50 53 uint_t tw_step;
51 54 } thread_walk_t;
52 55
53 56 int
54 57 thread_walk_init(mdb_walk_state_t *wsp)
55 58 {
56 59 thread_walk_t *twp = mdb_alloc(sizeof (thread_walk_t), UM_SLEEP);
57 60
58 61 if (wsp->walk_addr == NULL) {
59 62 if (mdb_readvar(&wsp->walk_addr, "allthreads") == -1) {
60 63 mdb_warn("failed to read 'allthreads'");
61 64 mdb_free(twp, sizeof (thread_walk_t));
62 65 return (WALK_ERR);
63 66 }
64 67
65 68 twp->tw_inproc = FALSE;
66 69
67 70 } else {
68 71 proc_t pr;
69 72
70 73 if (mdb_vread(&pr, sizeof (proc_t), wsp->walk_addr) == -1) {
71 74 mdb_warn("failed to read proc at %p", wsp->walk_addr);
72 75 mdb_free(twp, sizeof (thread_walk_t));
73 76 return (WALK_ERR);
74 77 }
75 78
76 79 wsp->walk_addr = (uintptr_t)pr.p_tlist;
77 80 twp->tw_inproc = TRUE;
78 81 }
79 82
80 83 twp->tw_thread = mdb_alloc(sizeof (kthread_t), UM_SLEEP);
81 84 twp->tw_last = wsp->walk_addr;
82 85 twp->tw_step = FALSE;
83 86
84 87 wsp->walk_data = twp;
85 88 return (WALK_NEXT);
86 89 }
87 90
88 91 int
89 92 thread_walk_step(mdb_walk_state_t *wsp)
90 93 {
91 94 thread_walk_t *twp = (thread_walk_t *)wsp->walk_data;
92 95 int status;
93 96
94 97 if (wsp->walk_addr == NULL)
95 98 return (WALK_DONE); /* Proc has 0 threads or allthreads = 0 */
96 99
97 100 if (twp->tw_step && wsp->walk_addr == twp->tw_last)
98 101 return (WALK_DONE); /* We've wrapped around */
99 102
100 103 if (mdb_vread(twp->tw_thread, sizeof (kthread_t),
101 104 wsp->walk_addr) == -1) {
102 105 mdb_warn("failed to read thread at %p", wsp->walk_addr);
103 106 return (WALK_DONE);
104 107 }
105 108
106 109 status = wsp->walk_callback(wsp->walk_addr, twp->tw_thread,
107 110 wsp->walk_cbdata);
108 111
109 112 if (twp->tw_inproc)
110 113 wsp->walk_addr = (uintptr_t)twp->tw_thread->t_forw;
111 114 else
112 115 wsp->walk_addr = (uintptr_t)twp->tw_thread->t_next;
113 116
114 117 twp->tw_step = TRUE;
115 118 return (status);
116 119 }
117 120
118 121 void
119 122 thread_walk_fini(mdb_walk_state_t *wsp)
120 123 {
121 124 thread_walk_t *twp = (thread_walk_t *)wsp->walk_data;
122 125
123 126 mdb_free(twp->tw_thread, sizeof (kthread_t));
124 127 mdb_free(twp, sizeof (thread_walk_t));
125 128 }
126 129
127 130 int
128 131 deathrow_walk_init(mdb_walk_state_t *wsp)
129 132 {
130 133 if (mdb_layered_walk("thread_deathrow", wsp) == -1) {
131 134 mdb_warn("couldn't walk 'thread_deathrow'");
132 135 return (WALK_ERR);
133 136 }
134 137
135 138 if (mdb_layered_walk("lwp_deathrow", wsp) == -1) {
136 139 mdb_warn("couldn't walk 'lwp_deathrow'");
137 140 return (WALK_ERR);
138 141 }
139 142
140 143 return (WALK_NEXT);
141 144 }
142 145
143 146 int
144 147 deathrow_walk_step(mdb_walk_state_t *wsp)
145 148 {
146 149 kthread_t t;
147 150 uintptr_t addr = wsp->walk_addr;
148 151
149 152 if (addr == NULL)
150 153 return (WALK_DONE);
151 154
152 155 if (mdb_vread(&t, sizeof (t), addr) == -1) {
153 156 mdb_warn("couldn't read deathrow thread at %p", addr);
154 157 return (WALK_ERR);
155 158 }
156 159
157 160 wsp->walk_addr = (uintptr_t)t.t_forw;
158 161
159 162 return (wsp->walk_callback(addr, &t, wsp->walk_cbdata));
160 163 }
161 164
162 165 int
163 166 thread_deathrow_walk_init(mdb_walk_state_t *wsp)
164 167 {
165 168 if (mdb_readvar(&wsp->walk_addr, "thread_deathrow") == -1) {
166 169 mdb_warn("couldn't read symbol 'thread_deathrow'");
167 170 return (WALK_ERR);
168 171 }
169 172
170 173 return (WALK_NEXT);
171 174 }
172 175
173 176 int
174 177 lwp_deathrow_walk_init(mdb_walk_state_t *wsp)
175 178 {
176 179 if (mdb_readvar(&wsp->walk_addr, "lwp_deathrow") == -1) {
177 180 mdb_warn("couldn't read symbol 'lwp_deathrow'");
178 181 return (WALK_ERR);
179 182 }
180 183
181 184 return (WALK_NEXT);
182 185 }
183 186
184 187
185 188 typedef struct dispq_walk {
186 189 int dw_npri;
187 190 uintptr_t dw_dispq;
188 191 uintptr_t dw_last;
189 192 } dispq_walk_t;
190 193
191 194 int
192 195 cpu_dispq_walk_init(mdb_walk_state_t *wsp)
193 196 {
194 197 uintptr_t addr = wsp->walk_addr;
195 198 dispq_walk_t *dw;
196 199 cpu_t cpu;
197 200 dispq_t dispq;
198 201 disp_t disp;
199 202
200 203 if (addr == NULL) {
201 204 mdb_warn("cpu_dispq walk needs a cpu_t address\n");
202 205 return (WALK_ERR);
203 206 }
204 207
205 208 if (mdb_vread(&cpu, sizeof (cpu_t), addr) == -1) {
206 209 mdb_warn("failed to read cpu_t at %p", addr);
207 210 return (WALK_ERR);
208 211 }
209 212
210 213 if (mdb_vread(&disp, sizeof (disp_t), (uintptr_t)cpu.cpu_disp) == -1) {
211 214 mdb_warn("failed to read disp_t at %p", cpu.cpu_disp);
212 215 return (WALK_ERR);
213 216 }
214 217
215 218 if (mdb_vread(&dispq, sizeof (dispq_t),
216 219 (uintptr_t)disp.disp_q) == -1) {
217 220 mdb_warn("failed to read dispq_t at %p", disp.disp_q);
218 221 return (WALK_ERR);
219 222 }
220 223
221 224 dw = mdb_alloc(sizeof (dispq_walk_t), UM_SLEEP);
222 225
223 226 dw->dw_npri = disp.disp_npri;
224 227 dw->dw_dispq = (uintptr_t)disp.disp_q;
225 228 dw->dw_last = (uintptr_t)dispq.dq_last;
226 229
227 230 wsp->walk_addr = (uintptr_t)dispq.dq_first;
228 231 wsp->walk_data = dw;
229 232
230 233 return (WALK_NEXT);
231 234 }
232 235
233 236 int
234 237 cpupart_dispq_walk_init(mdb_walk_state_t *wsp)
235 238 {
236 239 uintptr_t addr = wsp->walk_addr;
237 240 dispq_walk_t *dw;
238 241 cpupart_t cpupart;
239 242 dispq_t dispq;
240 243
241 244 if (addr == NULL) {
242 245 mdb_warn("cpupart_dispq walk needs a cpupart_t address\n");
243 246 return (WALK_ERR);
244 247 }
245 248
246 249 if (mdb_vread(&cpupart, sizeof (cpupart_t), addr) == -1) {
247 250 mdb_warn("failed to read cpupart_t at %p", addr);
248 251 return (WALK_ERR);
249 252 }
250 253
251 254 if (mdb_vread(&dispq, sizeof (dispq_t),
252 255 (uintptr_t)cpupart.cp_kp_queue.disp_q) == -1) {
253 256 mdb_warn("failed to read dispq_t at %p",
254 257 cpupart.cp_kp_queue.disp_q);
255 258 return (WALK_ERR);
256 259 }
257 260
258 261 dw = mdb_alloc(sizeof (dispq_walk_t), UM_SLEEP);
259 262
260 263 dw->dw_npri = cpupart.cp_kp_queue.disp_npri;
261 264 dw->dw_dispq = (uintptr_t)cpupart.cp_kp_queue.disp_q;
262 265 dw->dw_last = (uintptr_t)dispq.dq_last;
263 266
264 267 wsp->walk_addr = (uintptr_t)dispq.dq_first;
265 268 wsp->walk_data = dw;
266 269
267 270 return (WALK_NEXT);
268 271 }
269 272
270 273 int
271 274 dispq_walk_step(mdb_walk_state_t *wsp)
272 275 {
273 276 uintptr_t addr = wsp->walk_addr;
274 277 dispq_walk_t *dw = wsp->walk_data;
275 278 dispq_t dispq;
276 279 kthread_t t;
277 280
278 281 while (addr == NULL) {
279 282 if (--dw->dw_npri == 0)
280 283 return (WALK_DONE);
281 284
282 285 dw->dw_dispq += sizeof (dispq_t);
283 286
284 287 if (mdb_vread(&dispq, sizeof (dispq_t), dw->dw_dispq) == -1) {
285 288 mdb_warn("failed to read dispq_t at %p", dw->dw_dispq);
286 289 return (WALK_ERR);
287 290 }
288 291
289 292 dw->dw_last = (uintptr_t)dispq.dq_last;
290 293 addr = (uintptr_t)dispq.dq_first;
291 294 }
292 295
293 296 if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {
294 297 mdb_warn("failed to read kthread_t at %p", addr);
295 298 return (WALK_ERR);
296 299 }
297 300
298 301 if (addr == dw->dw_last)
299 302 wsp->walk_addr = NULL;
300 303 else
301 304 wsp->walk_addr = (uintptr_t)t.t_link;
302 305
303 306 return (wsp->walk_callback(addr, &t, wsp->walk_cbdata));
304 307 }
305 308
306 309 void
307 310 dispq_walk_fini(mdb_walk_state_t *wsp)
308 311 {
309 312 mdb_free(wsp->walk_data, sizeof (dispq_walk_t));
310 313 }
311 314
312 315 struct thread_state {
313 316 uint_t ts_state;
314 317 const char *ts_name;
315 318 } thread_states[] = {
316 319 { TS_FREE, "free" },
317 320 { TS_SLEEP, "sleep" },
318 321 { TS_RUN, "run" },
319 322 { TS_ONPROC, "onproc" },
320 323 { TS_ZOMB, "zomb" },
321 324 { TS_STOPPED, "stopped" },
322 325 { TS_WAIT, "wait" }
323 326 };
324 327 #define NUM_THREAD_STATES (sizeof (thread_states) / sizeof (*thread_states))
325 328
326 329 void
327 330 thread_state_to_text(uint_t state, char *out, size_t out_sz)
328 331 {
329 332 int idx;
330 333
331 334 for (idx = 0; idx < NUM_THREAD_STATES; idx++) {
332 335 struct thread_state *tsp = &thread_states[idx];
333 336 if (tsp->ts_state == state) {
334 337 mdb_snprintf(out, out_sz, "%s", tsp->ts_name);
335 338 return;
336 339 }
337 340 }
338 341 mdb_snprintf(out, out_sz, "inval/%02x", state);
339 342 }
340 343
341 344 int
342 345 thread_text_to_state(const char *state, uint_t *out)
343 346 {
344 347 int idx;
345 348
346 349 for (idx = 0; idx < NUM_THREAD_STATES; idx++) {
347 350 struct thread_state *tsp = &thread_states[idx];
348 351 if (strcasecmp(tsp->ts_name, state) == 0) {
349 352 *out = tsp->ts_state;
350 353 return (0);
351 354 }
352 355 }
353 356 return (-1);
354 357 }
355 358
356 359 void
357 360 thread_walk_states(void (*cbfunc)(uint_t, const char *, void *), void *cbarg)
358 361 {
359 362 int idx;
360 363
361 364 for (idx = 0; idx < NUM_THREAD_STATES; idx++) {
362 365 struct thread_state *tsp = &thread_states[idx];
363 366 cbfunc(tsp->ts_state, tsp->ts_name, cbarg);
364 367 }
365 368 }
366 369
367 370 #define TF_INTR 0x01
368 371 #define TF_PROC 0x02
369 372 #define TF_BLOCK 0x04
370 373 #define TF_SIG 0x08
371 374 #define TF_DISP 0x10
372 375 #define TF_MERGE 0x20
373 376
374 377 /*
375 378 * Display a kthread_t.
376 379 * This is a little complicated, as there is a lot of information that
377 380 * the user could be interested in. The flags "ipbsd" are used to
378 381 * indicate which subset of the thread's members are to be displayed
379 382 * ('i' is the default). If multiple options are specified, multiple
380 383 * sets of data will be displayed in a vaguely readable format. If the
381 384 * 'm' option is specified, all the selected sets will be merged onto a
382 385 * single line for the benefit of those using wider-than-normal
383 386 * terminals. Having a generic mechanism for doing this would be
384 387 * really useful, but is a project best left to another day.
385 388 */
386 389
387 390 int
388 391 thread(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
389 392 {
390 393 kthread_t t;
391 394 uint_t oflags = 0;
392 395 uint_t fflag = FALSE;
393 396 int first;
394 397 char stbuf[20];
395 398
396 399 /*
397 400 * "Gracefully" handle printing a boatload of stuff to the
398 401 * screen. If we are not printing our first set of data, and
399 402 * we haven't been instructed to merge sets together, output a
400 403 * newline and indent such that the thread addresses form a
401 404 * column of their own.
402 405 */
403 406 #define SPACER() \
404 407 if (first) { \
405 408 first = FALSE; \
406 409 } else if (!(oflags & TF_MERGE)) { \
407 410 mdb_printf("\n%?s", ""); \
408 411 }
409 412
410 413 if (!(flags & DCMD_ADDRSPEC)) {
411 414 if (mdb_walk_dcmd("thread", "thread", argc, argv) == -1) {
412 415 mdb_warn("can't walk threads");
413 416 return (DCMD_ERR);
414 417 }
415 418 return (DCMD_OK);
416 419 }
417 420
418 421 if (mdb_getopts(argc, argv,
419 422 'f', MDB_OPT_SETBITS, TRUE, &fflag,
420 423 'i', MDB_OPT_SETBITS, TF_INTR, &oflags,
421 424 'p', MDB_OPT_SETBITS, TF_PROC, &oflags,
422 425 'b', MDB_OPT_SETBITS, TF_BLOCK, &oflags,
423 426 's', MDB_OPT_SETBITS, TF_SIG, &oflags,
424 427 'd', MDB_OPT_SETBITS, TF_DISP, &oflags,
425 428 'm', MDB_OPT_SETBITS, TF_MERGE, &oflags, NULL) != argc)
426 429 return (DCMD_USAGE);
427 430
428 431 /*
429 432 * If no sets were specified, choose the 'i' set.
430 433 */
431 434 if (!(oflags & ~TF_MERGE))
432 435 #ifdef _LP64
433 436 oflags = TF_INTR;
434 437 #else
435 438 oflags = TF_INTR | TF_DISP | TF_MERGE;
436 439 #endif
437 440
438 441 /*
439 442 * Print the relevant headers; note use of SPACER().
440 443 */
441 444 if (DCMD_HDRSPEC(flags)) {
442 445 first = TRUE;
443 446 mdb_printf("%<u>%?s%</u>", "ADDR");
444 447 mdb_flush();
445 448
446 449 if (oflags & TF_PROC) {
447 450 SPACER();
448 451 mdb_printf("%<u> %?s %?s %?s%</u>",
449 452 "PROC", "LWP", "CRED");
450 453 }
451 454
452 455 if (oflags & TF_INTR) {
453 456 SPACER();
454 457 mdb_printf("%<u> %8s %4s %4s %4s %5s %5s %3s %?s%</u>",
455 458 "STATE", "FLG", "PFLG",
456 459 "SFLG", "PRI", "EPRI", "PIL", "INTR");
457 460 }
458 461
459 462 if (oflags & TF_BLOCK) {
460 463 SPACER();
461 464 mdb_printf("%<u> %?s %?s %?s %11s%</u>",
462 465 "WCHAN", "TS", "PITS", "SOBJ OPS");
463 466 }
464 467
465 468 if (oflags & TF_SIG) {
466 469 SPACER();
467 470 mdb_printf("%<u> %?s %16s %16s%</u>",
468 471 "SIGQUEUE", "SIG PEND", "SIG HELD");
469 472 }
470 473
471 474 if (oflags & TF_DISP) {
472 475 SPACER();
473 476 mdb_printf("%<u> %?s %5s %2s %-6s%</u>",
474 477 "DISPTIME", "BOUND", "PR", "SWITCH");
475 478 }
476 479 mdb_printf("\n");
477 480 }
478 481
479 482 if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {
480 483 mdb_warn("can't read kthread_t at %#lx", addr);
481 484 return (DCMD_ERR);
482 485 }
483 486
484 487 if (fflag && (t.t_state == TS_FREE))
485 488 return (DCMD_OK);
486 489
487 490 first = TRUE;
488 491 mdb_printf("%0?lx", addr);
489 492
490 493 /* process information */
491 494 if (oflags & TF_PROC) {
492 495 SPACER();
493 496 mdb_printf(" %?p %?p %?p", t.t_procp, t.t_lwp, t.t_cred);
494 497 }
495 498
496 499 /* priority/interrupt information */
497 500 if (oflags & TF_INTR) {
498 501 SPACER();
499 502 thread_state_to_text(t.t_state, stbuf, sizeof (stbuf));
500 503 if (t.t_intr == NULL) {
501 504 mdb_printf(" %-8s %4x %4x %4x %5d %5d %3d %?s",
502 505 stbuf, t.t_flag, t.t_proc_flag, t.t_schedflag,
503 506 t.t_pri, t.t_epri, t.t_pil, "n/a");
504 507 } else {
505 508 mdb_printf(" %-8s %4x %4x %4x %5d %5d %3d %?p",
506 509 stbuf, t.t_flag, t.t_proc_flag, t.t_schedflag,
507 510 t.t_pri, t.t_epri, t.t_pil, t.t_intr);
508 511 }
509 512 }
510 513
511 514 /* blocking information */
512 515 if (oflags & TF_BLOCK) {
513 516 SPACER();
514 517 (void) mdb_snprintf(stbuf, 20, "%a", t.t_sobj_ops);
515 518 stbuf[11] = '\0';
516 519 mdb_printf(" %?p %?p %?p %11s",
517 520 t.t_wchan, t.t_ts, t.t_prioinv, stbuf);
518 521 }
519 522
520 523 /* signal information */
521 524 if (oflags & TF_SIG) {
522 525 SPACER();
523 526 mdb_printf(" %?p %016llx %016llx",
524 527 t.t_sigqueue, t.t_sig, t.t_hold);
525 528 }
526 529
527 530 /* dispatcher stuff */
528 531 if (oflags & TF_DISP) {
529 532 SPACER();
530 533 mdb_printf(" %?lx %5d %2d ",
531 534 t.t_disp_time, t.t_bind_cpu, t.t_preempt);
532 535 if (t.t_disp_time != 0)
533 536 mdb_printf("t-%-4d",
534 537 (clock_t)mdb_get_lbolt() - t.t_disp_time);
535 538 else
536 539 mdb_printf("%-6s", "-");
537 540 }
538 541
539 542 mdb_printf("\n");
540 543
541 544 #undef SPACER
542 545
543 546 return (DCMD_OK);
544 547 }
545 548
546 549 void
547 550 thread_help(void)
548 551 {
549 552 mdb_printf(
550 553 "The flags -ipbsd control which information is displayed. When\n"
551 554 "combined, the fields are displayed on separate lines unless the\n"
552 555 "-m option is given.\n"
553 556 "\n"
↓ open down ↓ |
503 lines elided |
↑ open up ↑ |
554 557 "\t-b\tprint blocked thread state\n"
555 558 "\t-d\tprint dispatcher state\n"
556 559 "\t-f\tignore freed threads\n"
557 560 "\t-i\tprint basic thread state (default)\n"
558 561 "\t-m\tdisplay results on a single line\n"
559 562 "\t-p\tprint process and lwp state\n"
560 563 "\t-s\tprint signal state\n");
561 564 }
562 565
563 566 /*
567 + * Return a string description of the thread, including the ID and the thread
568 + * name.
569 + *
570 + * If ->t_name is NULL, and we're a system thread, we'll do a little more
571 + * spelunking to find a useful string to return.
572 + */
573 +int
574 +thread_getdesc(uintptr_t addr, boolean_t include_comm,
575 + char *buf, size_t bufsize)
576 +{
577 + char name[THREAD_NAME_MAX] = "";
578 + kthread_t t;
579 + proc_t p;
580 +
581 + bzero(buf, bufsize);
582 +
583 + if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {
584 + mdb_warn("failed to read kthread_t at %p", addr);
585 + return (-1);
586 + }
587 +
588 + if (t.t_tid == 0) {
589 + taskq_t tq;
590 +
591 + if (mdb_vread(&tq, sizeof (taskq_t),
592 + (uintptr_t)t.t_taskq) == -1)
593 + tq.tq_name[0] = '\0';
594 +
595 + if (t.t_name != NULL) {
596 + if (mdb_readstr(buf, bufsize,
597 + (uintptr_t)t.t_name) == -1) {
598 + mdb_warn("error reading thread name");
599 + }
600 + } else if (tq.tq_name[0] != '\0') {
601 + (void) mdb_snprintf(buf, bufsize, "tq:%s", tq.tq_name);
602 + } else {
603 + mdb_snprintf(buf, bufsize, "%a()", t.t_startpc);
604 + }
605 +
606 + return (buf[0] == '\0' ? -1 : 0);
607 + }
608 +
609 + if (include_comm && mdb_vread(&p, sizeof (proc_t),
610 + (uintptr_t)t.t_procp) == -1) {
611 + mdb_warn("failed to read proc at %p", t.t_procp);
612 + return (-1);
613 + }
614 +
615 + if (t.t_name != NULL) {
616 + if (mdb_readstr(name, sizeof (name), (uintptr_t)t.t_name) == -1)
617 + mdb_warn("error reading thread name");
618 +
619 + /*
620 + * Just to be safe -- if mdb_readstr() succeeds, it always NUL
621 + * terminates the output, but is unclear what it does on
622 + * failure. In that case we attempt to show any partial content
623 + * w/ the warning in case it's useful, but explicitly
624 + * NUL-terminate to be safe.
625 + */
626 + buf[bufsize - 1] = '\0';
627 + }
628 +
629 + if (name[0] != '\0') {
630 + if (include_comm) {
631 + (void) mdb_snprintf(buf, bufsize, "%s/%u [%s]",
632 + p.p_user.u_comm, t.t_tid, name);
633 + } else {
634 + (void) mdb_snprintf(buf, bufsize, "%u [%s]",
635 + t.t_tid, name);
636 + }
637 + } else {
638 + if (include_comm) {
639 + (void) mdb_snprintf(buf, bufsize, "%s/%u",
640 + p.p_user.u_comm, t.t_tid);
641 + } else {
642 + (void) mdb_snprintf(buf, bufsize, "%u", t.t_tid);
643 + }
644 + }
645 +
646 + return (buf[0] == '\0' ? -1 : 0);
647 +}
648 +
649 +/*
564 650 * List a combination of kthread_t and proc_t. Add stack traces in verbose mode.
565 651 */
566 652 int
567 653 threadlist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
568 654 {
569 655 int i;
570 656 uint_t count = 0;
571 657 uint_t verbose = FALSE;
572 658 uint_t notaskq = FALSE;
573 659 kthread_t t;
574 - taskq_t tq;
575 - proc_t p;
576 660 char cmd[80];
577 661 mdb_arg_t cmdarg;
578 662
579 663 if (!(flags & DCMD_ADDRSPEC)) {
580 664 if (mdb_walk_dcmd("thread", "threadlist", argc, argv) == -1) {
581 665 mdb_warn("can't walk threads");
582 666 return (DCMD_ERR);
583 667 }
584 668 return (DCMD_OK);
585 669 }
586 670
587 671 i = mdb_getopts(argc, argv,
588 672 't', MDB_OPT_SETBITS, TRUE, ¬askq,
589 673 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL);
590 674
591 675 if (i != argc) {
592 676 if (i != argc - 1 || !verbose)
593 677 return (DCMD_USAGE);
594 678
595 679 if (argv[i].a_type == MDB_TYPE_IMMEDIATE)
596 680 count = (uint_t)argv[i].a_un.a_val;
597 681 else
598 682 count = (uint_t)mdb_strtoull(argv[i].a_un.a_str);
599 683 }
600 684
601 685 if (DCMD_HDRSPEC(flags)) {
602 686 if (verbose)
603 687 mdb_printf("%<u>%?s %?s %?s %3s %3s %?s%</u>\n",
604 688 "ADDR", "PROC", "LWP", "CLS", "PRI", "WCHAN");
605 689 else
606 690 mdb_printf("%<u>%?s %?s %?s %s/%s%</u>\n",
607 691 "ADDR", "PROC", "LWP", "CMD", "LWPID");
608 692 }
609 693
610 694 if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {
↓ open down ↓ |
25 lines elided |
↑ open up ↑ |
611 695 mdb_warn("failed to read kthread_t at %p", addr);
612 696 return (DCMD_ERR);
613 697 }
614 698
615 699 if (notaskq && t.t_taskq != NULL)
616 700 return (DCMD_OK);
617 701
618 702 if (t.t_state == TS_FREE)
619 703 return (DCMD_OK);
620 704
621 - if (mdb_vread(&p, sizeof (proc_t), (uintptr_t)t.t_procp) == -1) {
622 - mdb_warn("failed to read proc at %p", t.t_procp);
623 - return (DCMD_ERR);
624 - }
705 + if (!verbose) {
706 + char desc[128];
625 707
626 - if (mdb_vread(&tq, sizeof (taskq_t), (uintptr_t)t.t_taskq) == -1)
627 - tq.tq_name[0] = '\0';
708 + if (thread_getdesc(addr, B_TRUE, desc, sizeof (desc)) == -1)
709 + return (DCMD_ERR);
628 710
629 - if (verbose) {
630 - mdb_printf("%0?p %?p %?p %3u %3d %?p\n",
631 - addr, t.t_procp, t.t_lwp, t.t_cid, t.t_pri, t.t_wchan);
711 + mdb_printf("%0?p %?p %?p %s\n", addr, t.t_procp, t.t_lwp, desc);
712 + return (DCMD_OK);
713 + }
632 714
633 - mdb_inc_indent(2);
715 + mdb_printf("%0?p %?p %?p %3u %3d %?p\n",
716 + addr, t.t_procp, t.t_lwp, t.t_cid, t.t_pri, t.t_wchan);
634 717
635 - mdb_printf("PC: %a", t.t_pc);
636 - if (t.t_tid == 0) {
637 - if (tq.tq_name[0] != '\0')
638 - mdb_printf(" TASKQ: %s\n", tq.tq_name);
639 - else
640 - mdb_printf(" THREAD: %a()\n", t.t_startpc);
641 - } else {
642 - mdb_printf(" CMD: %s\n", p.p_user.u_psargs);
643 - }
718 + mdb_inc_indent(2);
644 719
645 - mdb_snprintf(cmd, sizeof (cmd), "<.$c%d", count);
646 - cmdarg.a_type = MDB_TYPE_STRING;
647 - cmdarg.a_un.a_str = cmd;
720 + mdb_printf("PC: %a\n", t.t_pc);
648 721
649 - (void) mdb_call_dcmd("findstack", addr, flags, 1, &cmdarg);
722 + mdb_snprintf(cmd, sizeof (cmd), "<.$c%d", count);
723 + cmdarg.a_type = MDB_TYPE_STRING;
724 + cmdarg.a_un.a_str = cmd;
650 725
651 - mdb_dec_indent(2);
726 + (void) mdb_call_dcmd("findstack", addr, flags, 1, &cmdarg);
652 727
653 - mdb_printf("\n");
654 - } else {
655 - mdb_printf("%0?p %?p %?p", addr, t.t_procp, t.t_lwp);
656 - if (t.t_tid == 0) {
657 - if (tq.tq_name[0] != '\0')
658 - mdb_printf(" tq:%s\n", tq.tq_name);
659 - else
660 - mdb_printf(" %a()\n", t.t_startpc);
661 - } else {
662 - mdb_printf(" %s/%u\n", p.p_user.u_comm, t.t_tid);
663 - }
664 - }
728 + mdb_dec_indent(2);
665 729
730 + mdb_printf("\n");
731 +
666 732 return (DCMD_OK);
667 733 }
668 734
669 735 void
670 736 threadlist_help(void)
671 737 {
672 738 mdb_printf(
673 739 " -v print verbose output including C stack trace\n"
674 740 " -t skip threads belonging to a taskq\n"
675 741 " count print no more than count arguments (default 0)\n");
676 742 }
677 743
678 744 static size_t
679 745 stk_compute_percent(caddr_t t_stk, caddr_t t_stkbase, caddr_t sp)
680 746 {
681 747 size_t percent;
682 748 size_t s;
683 749
684 750 if (t_stk > t_stkbase) {
685 751 /* stack grows down */
686 752 if (sp > t_stk) {
687 753 return (0);
688 754 }
689 755 if (sp < t_stkbase) {
690 756 return (100);
691 757 }
692 758 percent = t_stk - sp + 1;
693 759 s = t_stk - t_stkbase + 1;
694 760 } else {
695 761 /* stack grows up */
696 762 if (sp < t_stk) {
697 763 return (0);
698 764 }
699 765 if (sp > t_stkbase) {
700 766 return (100);
701 767 }
702 768 percent = sp - t_stk + 1;
703 769 s = t_stkbase - t_stk + 1;
704 770 }
705 771 percent = ((100 * percent) / s) + 1;
706 772 if (percent > 100) {
707 773 percent = 100;
708 774 }
↓ open down ↓ |
33 lines elided |
↑ open up ↑ |
709 775 return (percent);
710 776 }
711 777
712 778 /*
713 779 * Display kthread stack infos.
714 780 */
715 781 int
716 782 stackinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
717 783 {
718 784 kthread_t t;
719 - proc_t p;
720 785 uint64_t *ptr; /* pattern pointer */
721 786 caddr_t start; /* kernel stack start */
722 787 caddr_t end; /* kernel stack end */
723 788 caddr_t ustack; /* userland copy of kernel stack */
724 789 size_t usize; /* userland copy of kernel stack size */
725 790 caddr_t ustart; /* userland copy of kernel stack, aligned start */
726 791 caddr_t uend; /* userland copy of kernel stack, aligned end */
727 792 size_t percent = 0;
728 793 uint_t all = FALSE; /* don't show TS_FREE kthread by default */
729 794 uint_t history = FALSE;
730 795 int i = 0;
731 796 unsigned int ukmem_stackinfo;
732 797 uintptr_t allthreads;
798 + char tdesc[128] = "";
733 799
734 800 /* handle options */
735 801 if (mdb_getopts(argc, argv,
736 802 'a', MDB_OPT_SETBITS, TRUE, &all,
737 803 'h', MDB_OPT_SETBITS, TRUE, &history, NULL) != argc) {
738 804 return (DCMD_USAGE);
739 805 }
740 806
741 807 /* walk all kthread if needed */
742 808 if ((history == FALSE) && !(flags & DCMD_ADDRSPEC)) {
743 809 if (mdb_walk_dcmd("thread", "stackinfo", argc, argv) == -1) {
744 810 mdb_warn("can't walk threads");
745 811 return (DCMD_ERR);
746 812 }
747 813 return (DCMD_OK);
748 814 }
749 815
750 816 /* read 'kmem_stackinfo' */
751 817 if (mdb_readsym(&ukmem_stackinfo, sizeof (ukmem_stackinfo),
752 818 "kmem_stackinfo") == -1) {
753 819 mdb_warn("failed to read 'kmem_stackinfo'\n");
754 820 ukmem_stackinfo = 0;
755 821 }
756 822
757 823 /* read 'allthreads' */
758 824 if (mdb_readsym(&allthreads, sizeof (kthread_t *),
759 825 "allthreads") == -1) {
760 826 mdb_warn("failed to read 'allthreads'\n");
761 827 allthreads = NULL;
762 828 }
763 829
764 830 if (history == TRUE) {
765 831 kmem_stkinfo_t *log;
766 832 uintptr_t kaddr;
767 833
↓ open down ↓ |
25 lines elided |
↑ open up ↑ |
768 834 mdb_printf("Dead kthreads stack usage history:\n");
769 835 if (ukmem_stackinfo == 0) {
770 836 mdb_printf("Tunable kmem_stackinfo is unset, history ");
771 837 mdb_printf("feature is off.\nUse ::help stackinfo ");
772 838 mdb_printf("for more details.\n");
773 839 return (DCMD_OK);
774 840 }
775 841
776 842 mdb_printf("%<u>%?s%</u>", "THREAD");
777 843 mdb_printf(" %<u>%?s%</u>", "STACK");
778 - mdb_printf("%<u>%s%</u>", " SIZE MAX CMD/LWPID or STARTPC");
844 + mdb_printf("%<u>%s%</u>", " SIZE MAX LWP");
779 845 mdb_printf("\n");
780 846 usize = KMEM_STKINFO_LOG_SIZE * sizeof (kmem_stkinfo_t);
781 847 log = (kmem_stkinfo_t *)mdb_alloc(usize, UM_SLEEP);
782 848 if (mdb_readsym(&kaddr, sizeof (kaddr),
783 849 "kmem_stkinfo_log") == -1) {
784 850 mdb_free((void *)log, usize);
785 851 mdb_warn("failed to read 'kmem_stkinfo_log'\n");
786 852 return (DCMD_ERR);
787 853 }
788 854 if (kaddr == NULL) {
789 855 mdb_free((void *)log, usize);
790 856 return (DCMD_OK);
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
791 857 }
792 858 if (mdb_vread(log, usize, kaddr) == -1) {
793 859 mdb_free((void *)log, usize);
794 860 mdb_warn("failed to read %p\n", kaddr);
795 861 return (DCMD_ERR);
796 862 }
797 863 for (i = 0; i < KMEM_STKINFO_LOG_SIZE; i++) {
798 864 if (log[i].kthread == NULL) {
799 865 continue;
800 866 }
801 - mdb_printf("%0?p %0?p %6x %3d%%",
867 +
868 + (void) thread_getdesc((uintptr_t)log[i].kthread,
869 + B_TRUE, tdesc, sizeof (tdesc));
870 +
871 + mdb_printf("%0?p %0?p %6x %3d%% %s\n",
802 872 log[i].kthread,
803 873 log[i].start,
804 874 (uint_t)log[i].stksz,
805 - (int)log[i].percent);
806 - if (log[i].t_tid != 0) {
807 - mdb_printf(" %s/%u\n",
808 - log[i].cmd, log[i].t_tid);
809 - } else {
810 - mdb_printf(" %p (%a)\n", log[i].t_startpc,
811 - log[i].t_startpc);
812 - }
875 + (int)log[i].percent, tdesc);
813 876 }
814 877 mdb_free((void *)log, usize);
815 878 return (DCMD_OK);
816 879 }
817 880
818 881 /* display header */
819 882 if (DCMD_HDRSPEC(flags)) {
820 883 if (ukmem_stackinfo == 0) {
821 884 mdb_printf("Tunable kmem_stackinfo is unset, ");
822 885 mdb_printf("MAX value is not available.\n");
823 886 mdb_printf("Use ::help stackinfo for more details.\n");
824 887 }
825 888 mdb_printf("%<u>%?s%</u>", "THREAD");
826 889 mdb_printf(" %<u>%?s%</u>", "STACK");
827 - mdb_printf("%<u>%s%</u>", " SIZE CUR MAX CMD/LWPID");
890 + mdb_printf("%<u>%s%</u>", " SIZE CUR MAX LWP");
828 891 mdb_printf("\n");
829 892 }
830 893
831 894 /* read kthread */
832 895 if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {
833 896 mdb_warn("can't read kthread_t at %#lx\n", addr);
834 897 return (DCMD_ERR);
835 898 }
836 899
837 900 if (t.t_state == TS_FREE && all == FALSE) {
838 901 return (DCMD_OK);
839 902 }
840 903
841 - /* read proc */
842 - if (mdb_vread(&p, sizeof (proc_t), (uintptr_t)t.t_procp) == -1) {
843 - mdb_warn("failed to read proc at %p\n", t.t_procp);
844 - return (DCMD_ERR);
845 - }
846 -
847 904 /*
848 905 * Stack grows up or down, see thread_create(),
849 906 * compute stack memory aera start and end (start < end).
850 907 */
851 908 if (t.t_stk > t.t_stkbase) {
852 909 /* stack grows down */
853 910 start = t.t_stkbase;
854 911 end = t.t_stk;
855 912 } else {
856 913 /* stack grows up */
857 914 start = t.t_stk;
858 915 end = t.t_stkbase;
859 916 }
860 917
861 918 /* display stack info */
862 919 mdb_printf("%0?p %0?p", addr, start);
863 920
864 921 /* (end - start), kernel stack size as found in kthread_t */
865 922 if ((end <= start) || ((end - start) > (1024 * 1024))) {
866 923 /* negative or stack size > 1 meg, assume bogus */
867 924 mdb_warn(" t_stk/t_stkbase problem\n");
868 925 return (DCMD_ERR);
869 926 }
870 927
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
871 928 /* display stack size */
872 929 mdb_printf(" %6x", end - start);
873 930
874 931 /* display current stack usage */
875 932 percent = stk_compute_percent(t.t_stk, t.t_stkbase,
876 933 (caddr_t)t.t_sp + STACK_BIAS);
877 934
878 935 mdb_printf(" %3d%%", percent);
879 936 percent = 0;
880 937
938 + (void) thread_getdesc(addr, B_TRUE, tdesc, sizeof (tdesc));
939 +
881 940 if (ukmem_stackinfo == 0) {
882 - mdb_printf(" n/a");
883 - if (t.t_tid == 0) {
884 - mdb_printf(" %a()", t.t_startpc);
885 - } else {
886 - mdb_printf(" %s/%u", p.p_user.u_comm, t.t_tid);
887 - }
888 - mdb_printf("\n");
941 + mdb_printf(" n/a %s\n", tdesc);
889 942 return (DCMD_OK);
890 943 }
891 944
892 945 if ((((uintptr_t)start) & 0x7) != 0) {
893 946 start = (caddr_t)((((uintptr_t)start) & (~0x7)) + 8);
894 947 }
895 948 end = (caddr_t)(((uintptr_t)end) & (~0x7));
896 949 /* size to scan in userland copy of kernel stack */
897 950 usize = end - start; /* is a multiple of 8 bytes */
898 951
899 952 /*
900 953 * Stackinfo pattern size is 8 bytes. Ensure proper 8 bytes
901 954 * alignement for ustart and uend, in boundaries.
902 955 */
903 956 ustart = ustack = (caddr_t)mdb_alloc(usize + 8, UM_SLEEP);
904 957 if ((((uintptr_t)ustart) & 0x7) != 0) {
905 958 ustart = (caddr_t)((((uintptr_t)ustart) & (~0x7)) + 8);
906 959 }
907 960 uend = ustart + usize;
908 961
909 962 /* read the kernel stack */
910 963 if (mdb_vread(ustart, usize, (uintptr_t)start) != usize) {
911 964 mdb_free((void *)ustack, usize + 8);
912 965 mdb_printf("\n");
913 966 mdb_warn("couldn't read entire stack\n");
914 967 return (DCMD_ERR);
915 968 }
916 969
917 970 /* scan the stack */
918 971 if (t.t_stk > t.t_stkbase) {
919 972 /* stack grows down */
920 973 #if defined(__i386) || defined(__amd64)
921 974 /*
922 975 * 6 longs are pushed on stack, see thread_load(). Skip
923 976 * them, so if kthread has never run, percent is zero.
924 977 * 8 bytes alignement is preserved for a 32 bit kernel,
925 978 * 6 x 4 = 24, 24 is a multiple of 8.
926 979 */
927 980 uend -= (6 * sizeof (long));
928 981 #endif
929 982 ptr = (uint64_t *)((void *)ustart);
930 983 while (ptr < (uint64_t *)((void *)uend)) {
931 984 if (*ptr != KMEM_STKINFO_PATTERN) {
932 985 percent = stk_compute_percent(uend,
933 986 ustart, (caddr_t)ptr);
934 987 break;
935 988 }
936 989 ptr++;
937 990 }
938 991 } else {
939 992 /* stack grows up */
940 993 ptr = (uint64_t *)((void *)uend);
941 994 ptr--;
942 995 while (ptr >= (uint64_t *)((void *)ustart)) {
943 996 if (*ptr != KMEM_STKINFO_PATTERN) {
944 997 percent = stk_compute_percent(ustart,
945 998 uend, (caddr_t)ptr);
946 999 break;
947 1000 }
948 1001 ptr--;
949 1002 }
950 1003 }
↓ open down ↓ |
52 lines elided |
↑ open up ↑ |
951 1004
952 1005 /* thread 't0' stack is not created by thread_create() */
953 1006 if (addr == allthreads) {
954 1007 percent = 0;
955 1008 }
956 1009 if (percent != 0) {
957 1010 mdb_printf(" %3d%%", percent);
958 1011 } else {
959 1012 mdb_printf(" n/a");
960 1013 }
961 - if (t.t_tid == 0) {
962 - mdb_printf(" %a()", t.t_startpc);
963 - } else {
964 - mdb_printf(" %s/%u", p.p_user.u_comm, t.t_tid);
965 - }
966 - mdb_printf("\n");
1014 +
1015 + mdb_printf(" %s\n", tdesc);
1016 +
967 1017 mdb_free((void *)ustack, usize + 8);
968 1018 return (DCMD_OK);
969 1019 }
970 1020
971 1021 void
972 1022 stackinfo_help(void)
973 1023 {
974 1024 mdb_printf(
975 1025 "Shows kernel stacks real utilization, if /etc/system "
976 1026 "kmem_stackinfo tunable\n");
977 1027 mdb_printf(
978 1028 "(an unsigned integer) is non zero at kthread creation time. ");
979 1029 mdb_printf("For example:\n");
980 1030 mdb_printf(
981 - " THREAD STACK SIZE CUR MAX CMD/LWPID\n");
1031 + " THREAD STACK SIZE CUR MAX LWP\n");
982 1032 mdb_printf(
983 1033 "ffffff014f5f2c20 ffffff0004153000 4f00 4%% 43%% init/1\n");
984 1034 mdb_printf(
985 1035 "The stack size utilization for this kthread is at 4%%"
986 1036 " of its maximum size,\n");
987 1037 mdb_printf(
988 1038 "but has already used up to 43%%, stack size is 4f00 bytes.\n");
989 1039 mdb_printf(
990 1040 "MAX value can be shown as n/a (not available):\n");
991 1041 mdb_printf(
992 1042 " - for the very first kthread (sched/1)\n");
993 1043 mdb_printf(
994 1044 " - kmem_stackinfo was zero at kthread creation time\n");
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
995 1045 mdb_printf(
996 1046 " - kthread has not yet run\n");
997 1047 mdb_printf("\n");
998 1048 mdb_printf("Options:\n");
999 1049 mdb_printf(
1000 1050 "-a shows also TS_FREE kthreads (interrupt kthreads)\n");
1001 1051 mdb_printf(
1002 1052 "-h shows history, dead kthreads that used their "
1003 1053 "kernel stack the most\n");
1004 1054 mdb_printf(
1005 - "\nSee Solaris Modular Debugger Guide for detailed usage.\n");
1055 + "\nSee illumos Modular Debugger Guide for detailed usage.\n");
1006 1056 mdb_flush();
1007 1057 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX