Print this page
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/mdb/common/modules/libc/libc.c
+++ new/usr/src/cmd/mdb/common/modules/libc/libc.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) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright (c) 2012 by Delphix. All rights reserved.
25 25 * Copyright 2016, Joyent, Inc.
26 26 */
27 27
28 28 #include <sys/mdb_modapi.h>
29 29 #include <mdb/mdb_whatis.h>
30 30 #include <mdb/mdb_ctf.h>
31 31 #include <procfs.h>
32 32 #include <ucontext.h>
33 33 #include <siginfo.h>
34 34 #include <signal.h>
35 35 #include <setjmp.h>
36 36 #include <string.h>
37 37 #include <thr_uberdata.h>
38 38 #include "findstack.h"
39 39
40 40 static const char *
41 41 stack_flags(const stack_t *sp)
42 42 {
43 43 static char buf[32];
44 44
45 45 if (sp->ss_flags == 0)
46 46 (void) strcpy(buf, " 0");
47 47 else if (sp->ss_flags & ~(SS_ONSTACK | SS_DISABLE))
48 48 (void) mdb_snprintf(buf, sizeof (buf), " 0x%x", sp->ss_flags);
49 49 else {
50 50 buf[0] = '\0';
51 51 if (sp->ss_flags & SS_ONSTACK)
52 52 (void) strcat(buf, "|ONSTACK");
53 53 if (sp->ss_flags & SS_DISABLE)
54 54 (void) strcat(buf, "|DISABLE");
55 55 }
56 56
57 57 return (buf + 1);
58 58 }
59 59
60 60 /*ARGSUSED*/
61 61 static int
62 62 d_jmp_buf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
63 63 {
64 64 jmp_buf jb;
65 65 const ulong_t *b = (const ulong_t *)jb;
66 66
67 67 if (argc != 0)
68 68 return (DCMD_USAGE);
69 69
70 70 if (mdb_vread(&jb, sizeof (jb), addr) != sizeof (jb)) {
71 71 mdb_warn("failed to read jmp_buf at %p", addr);
72 72 return (DCMD_ERR);
73 73 }
74 74
75 75 #if defined(__sparc)
76 76 mdb_printf(" %%sp = 0x%lx\n", b[1]);
77 77 mdb_printf(" %%pc = 0x%lx %lA\n", b[2], b[2]);
78 78 mdb_printf(" %%fp = 0x%lx\n", b[3]);
79 79 mdb_printf(" %%i7 = 0x%lx %lA\n", b[4], b[4]);
80 80 #elif defined(__amd64)
81 81 mdb_printf(" %%rbx = 0x%lx\n", b[0]);
82 82 mdb_printf(" %%r12 = 0x%lx\n", b[1]);
83 83 mdb_printf(" %%r13 = 0x%lx\n", b[2]);
84 84 mdb_printf(" %%r14 = 0x%lx\n", b[3]);
85 85 mdb_printf(" %%r15 = 0x%lx\n", b[4]);
86 86 mdb_printf(" %%rbp = 0x%lx\n", b[5]);
87 87 mdb_printf(" %%rsp = 0x%lx\n", b[6]);
88 88 mdb_printf(" %%rip = 0x%lx %lA\n", b[7], b[7]);
89 89 #elif defined(__i386)
90 90 mdb_printf(" %%ebx = 0x%lx\n", b[0]);
91 91 mdb_printf(" %%esi = 0x%lx\n", b[1]);
92 92 mdb_printf(" %%edi = 0x%lx\n", b[2]);
93 93 mdb_printf(" %%ebp = 0x%lx\n", b[3]);
94 94 mdb_printf(" %%esp = 0x%lx\n", b[4]);
95 95 mdb_printf(" %%eip = 0x%lx %lA\n", b[5], b[5]);
96 96 #endif
97 97 return (DCMD_OK);
98 98 }
99 99
100 100 const mdb_bitmask_t uc_flags_bits[] = {
101 101 { "UC_SIGMASK", UC_SIGMASK, UC_SIGMASK },
102 102 { "UC_STACK", UC_STACK, UC_STACK },
103 103 { "UC_CPU", UC_CPU, UC_CPU },
104 104 { "UC_FPU", UC_FPU, UC_FPU },
105 105 #if defined(UC_INTR)
106 106 { "UC_INTR", UC_INTR, UC_INTR },
107 107 #endif
108 108 #if defined(UC_ASR)
109 109 { "UC_ASR", UC_ASR, UC_ASR },
110 110 #endif
111 111 { NULL, 0, 0 }
112 112 };
113 113
114 114 /*ARGSUSED*/
115 115 static int
116 116 d_ucontext(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
117 117 {
118 118 ucontext_t uc;
119 119
120 120 if (argc != 0)
121 121 return (DCMD_USAGE);
122 122
123 123 if (mdb_vread(&uc, sizeof (uc), addr) != sizeof (uc)) {
124 124 mdb_warn("failed to read ucontext at %p", addr);
125 125 return (DCMD_ERR);
126 126 }
127 127
128 128 mdb_printf(" flags = 0x%lx <%b>\n", uc.uc_flags,
129 129 (uint_t)uc.uc_flags, uc_flags_bits);
130 130 mdb_printf(" link = 0x%p\n", uc.uc_link);
131 131 mdb_printf(" sigmask = 0x%08x 0x%08x 0x%08x 0x%08x\n",
132 132 uc.uc_sigmask.__sigbits[0], uc.uc_sigmask.__sigbits[1],
133 133 uc.uc_sigmask.__sigbits[2], uc.uc_sigmask.__sigbits[3]);
134 134 mdb_printf(" stack = sp 0x%p size 0x%lx flags %s\n",
135 135 uc.uc_stack.ss_sp, uc.uc_stack.ss_size, stack_flags(&uc.uc_stack));
136 136 mdb_printf(" mcontext = 0x%p\n",
137 137 addr + OFFSETOF(ucontext_t, uc_mcontext));
138 138 mdb_printf(" brand = 0x%p 0x%p 0x%p\n",
139 139 uc.uc_brand_data[0], uc.uc_brand_data[1], uc.uc_brand_data[2]);
140 140
141 141 return (DCMD_OK);
142 142 }
143 143
144 144 /*ARGSUSED*/
145 145 static int
146 146 d_sigjmp_buf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
147 147 {
148 148 #if defined(__sparc)
149 149 struct {
150 150 int sjs_flags;
151 151 greg_t sjs_sp;
152 152 greg_t sjs_pc;
153 153 greg_t sjs_fp;
154 154 greg_t sjs_i7;
155 155 ucontext_t *sjs_uclink;
156 156 ulong_t sjs_pad[_JBLEN - 6];
157 157 sigset_t sjs_sigmask;
158 158 #if defined(_LP64)
159 159 greg_t sjs_asi;
160 160 greg_t sjs_fprs;
161 161 #endif
162 162 stack_t sjs_stack;
163 163 } s;
164 164
165 165 if (argc != 0)
166 166 return (DCMD_USAGE);
167 167
168 168 if (mdb_vread(&s, sizeof (s), addr) != sizeof (s)) {
169 169 mdb_warn("failed to read sigjmp_buf at %p", addr);
170 170 return (DCMD_ERR);
171 171 }
172 172
173 173 mdb_printf(" flags = 0x%x\n", s.sjs_flags);
174 174 mdb_printf(" %%sp = 0x%lx %lA\n", s.sjs_sp, s.sjs_sp);
175 175 mdb_printf(" %%pc = 0x%lx %lA\n", s.sjs_pc, s.sjs_pc);
176 176 mdb_printf(" %%fp = 0x%lx %lA\n", s.sjs_fp, s.sjs_fp);
177 177 mdb_printf(" %%i7 = 0x%lx %lA\n", s.sjs_i7, s.sjs_i7);
178 178 mdb_printf(" uclink = %p\n", s.sjs_uclink);
179 179 mdb_printf(" sigset = 0x%08x 0x%08x 0x%08x 0x%08x\n",
180 180 s.sjs_sigmask.__sigbits[0], s.sjs_sigmask.__sigbits[1],
181 181 s.sjs_sigmask.__sigbits[2], s.sjs_sigmask.__sigbits[3]);
182 182 #if defined(_LP64)
183 183 mdb_printf(" %%asi = 0x%lx\n", s.sjs_asi);
184 184 mdb_printf(" %%fprs = 0x%lx\n", s.sjs_fprs);
185 185 #endif
186 186 mdb_printf(" stack = sp 0x%p size 0x%lx flags %s\n",
187 187 s.sjs_stack.ss_sp, s.sjs_stack.ss_size, stack_flags(&s.sjs_stack));
188 188
189 189 return (DCMD_OK);
190 190
191 191 #elif defined(__i386) || defined(__amd64)
192 192 return (d_ucontext(addr, flags, argc, argv));
193 193 #endif
194 194 }
195 195
196 196 /*ARGSUSED*/
197 197 static int
198 198 d_siginfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
199 199 {
200 200 static const char *const msname[] = {
201 201 "USER", "SYSTEM", "TRAP", "TFAULT", "DFAULT", "KFAULT",
202 202 "USER_LOCK", "SLEEP", "WAIT_CPU", "STOPPED"
203 203 };
204 204
205 205 char signame[SIG2STR_MAX];
206 206 siginfo_t si;
207 207 int i;
208 208
209 209 if (argc != 0)
210 210 return (DCMD_USAGE);
211 211
212 212 if (mdb_vread(&si, sizeof (si), addr) != sizeof (si)) {
213 213 mdb_warn("failed to read siginfo at %p", addr);
214 214 return (DCMD_ERR);
215 215 }
216 216
217 217 if (sig2str(si.si_signo, signame) == -1)
218 218 (void) strcpy(signame, "unknown");
219 219
220 220 mdb_printf(" signal %5d (%s)\n", si.si_signo, signame);
221 221 mdb_printf(" code %5d (", si.si_code);
222 222
223 223 switch (si.si_code) {
224 224 case SI_NOINFO:
225 225 mdb_printf("no info");
226 226 break;
227 227 case SI_DTRACE:
228 228 mdb_printf("from DTrace raise() action");
229 229 break;
230 230 case SI_RCTL:
231 231 mdb_printf("from rctl action");
232 232 break;
233 233 case SI_USER:
234 234 mdb_printf("user generated via kill");
235 235 break;
236 236 case SI_LWP:
237 237 mdb_printf("user generated via lwp_kill");
238 238 break;
239 239 case SI_QUEUE:
240 240 mdb_printf("user generated via sigqueue");
241 241 break;
242 242 case SI_TIMER:
243 243 mdb_printf("from timer expiration");
244 244 break;
245 245 case SI_ASYNCIO:
246 246 mdb_printf("from async i/o completion");
247 247 break;
248 248 case SI_MESGQ:
249 249 mdb_printf("from message arrival");
250 250 break;
251 251 default:
252 252 if (SI_FROMUSER(&si))
253 253 mdb_printf("from user process");
254 254 else
255 255 mdb_printf("from kernel");
256 256 }
257 257
258 258 mdb_printf(")\n errno %5d (%s)\n",
259 259 si.si_errno, strerror(si.si_errno));
260 260
261 261 if (si.si_code == SI_USER || si.si_code == SI_QUEUE) {
262 262 mdb_printf(" signal sent from PID %d (uid %d)\n",
263 263 si.si_pid, si.si_uid);
264 264 }
265 265
266 266 if (si.si_code == SI_QUEUE) {
267 267 mdb_printf(" signal value = 0t%d / %p\n",
268 268 si.si_value.sival_int, si.si_value.sival_ptr);
269 269 }
270 270
271 271 switch (si.si_signo) {
272 272 case SIGCLD:
273 273 mdb_printf(" signal sent from child PID %d (uid %d)\n",
274 274 si.si_pid, si.si_uid);
275 275 mdb_printf(" usr time = 0t%ld ticks, sys time = 0t%ld ticks\n",
276 276 si.si_utime, si.si_stime);
277 277 mdb_printf(" wait status = 0x%x\n", si.si_status);
278 278 break;
279 279
280 280 case SIGSEGV:
281 281 case SIGBUS:
282 282 case SIGILL:
283 283 case SIGTRAP:
284 284 case SIGFPE:
285 285 mdb_printf(" fault address = 0x%p\n trapno = %d\n",
286 286 si.si_addr, si.si_trapno);
287 287 mdb_printf(" instruction address = 0x%p %lA\n",
288 288 si.si_pc, si.si_pc);
289 289 break;
290 290
291 291 case SIGPOLL:
292 292 case SIGXFSZ:
293 293 mdb_printf(" fd = %d band = 0x%lx\n",
294 294 si.si_fd, si.si_band);
295 295 break;
296 296
297 297 case SIGPROF:
298 298 mdb_printf(" last fault address = 0x%p fault type = %d\n",
299 299 si.si_faddr, si.si_fault);
300 300 mdb_printf(" timestamp = 0t%ld sec 0t%ld nsec\n",
301 301 si.si_tstamp.tv_sec, si.si_tstamp.tv_nsec);
302 302
303 303 if (si.__data.__prof.__syscall != 0) {
304 304 mdb_printf(" system call %d (", si.si_syscall);
305 305 if (si.si_nsysarg > 0) {
306 306 mdb_printf("%lx", si.si_sysarg[0]);
307 307 for (i = 1; i < si.si_nsysarg; i++)
308 308 mdb_printf(", %lx", si.si_sysarg[i]);
309 309 }
310 310 mdb_printf(" )\n");
311 311 }
312 312
313 313 for (i = 0; i < sizeof (msname) / sizeof (msname[0]); i++) {
314 314 mdb_printf(" mstate[\"%s\"] = %d\n",
315 315 msname[i], si.si_mstate[i]);
316 316 }
317 317 break;
318 318 }
319 319
320 320 return (DCMD_OK);
321 321 }
322 322
323 323 static int
324 324 uc_walk_step(mdb_walk_state_t *wsp)
325 325 {
326 326 uintptr_t addr = wsp->walk_addr;
327 327 ucontext_t uc;
328 328
329 329 if (addr == NULL)
330 330 return (WALK_DONE);
331 331
332 332 if (mdb_vread(&uc, sizeof (uc), addr) != sizeof (uc)) {
333 333 mdb_warn("failed to read ucontext at %p", addr);
334 334 return (WALK_ERR);
335 335 }
336 336
337 337 wsp->walk_addr = (uintptr_t)uc.uc_link;
338 338 return (wsp->walk_callback(addr, &uc, wsp->walk_cbdata));
339 339 }
340 340
341 341 static int
342 342 oldc_walk_init(mdb_walk_state_t *wsp)
343 343 {
344 344 ssize_t nbytes = mdb_get_xdata("lwpstatus", NULL, 0);
345 345
346 346 if (nbytes <= 0) {
347 347 mdb_warn("lwpstatus information not available");
348 348 return (WALK_ERR);
349 349 }
350 350
351 351 if (wsp->walk_addr != NULL) {
352 352 mdb_warn("walker only supports global walk\n");
353 353 return (WALK_ERR);
354 354 }
355 355
356 356 wsp->walk_addr = nbytes; /* Use walk_addr to track size */
357 357 wsp->walk_data = mdb_alloc(nbytes, UM_SLEEP);
358 358
359 359 if (mdb_get_xdata("lwpstatus", wsp->walk_data, nbytes) != nbytes) {
360 360 mdb_warn("failed to read lwpstatus information");
361 361 mdb_free(wsp->walk_data, nbytes);
362 362 return (WALK_ERR);
363 363 }
364 364
365 365 wsp->walk_arg = wsp->walk_data; /* Use walk_arg to track pointer */
366 366 return (WALK_NEXT);
367 367 }
368 368
369 369 static int
370 370 oldc_walk_step(mdb_walk_state_t *wsp)
371 371 {
372 372 const lwpstatus_t *lsp, *end;
373 373
374 374 end = (const lwpstatus_t *)((uintptr_t)wsp->walk_data + wsp->walk_addr);
375 375 lsp = wsp->walk_arg;
376 376
377 377 wsp->walk_arg = (void *)(lsp + 1);
378 378
379 379 if (lsp < end) {
380 380 uintptr_t addr = lsp->pr_oldcontext;
381 381 ucontext_t uc;
382 382
383 383 if (addr == NULL)
384 384 return (WALK_NEXT);
385 385
386 386 if (mdb_vread(&uc, sizeof (uc), addr) != sizeof (uc)) {
387 387 mdb_warn("failed to read ucontext at %p", addr);
388 388 return (WALK_NEXT);
389 389 }
390 390
391 391 return (wsp->walk_callback(addr, &uc, wsp->walk_cbdata));
392 392 }
393 393
394 394 return (WALK_DONE);
395 395 }
396 396
397 397 static void
398 398 oldc_walk_fini(mdb_walk_state_t *wsp)
399 399 {
400 400 mdb_free(wsp->walk_data, wsp->walk_addr); /* walk_addr has size */
401 401 }
402 402
403 403 /*
404 404 * ==================== threads ==========================
405 405 * These are the interfaces that used to require libthread.
406 406 * Now, libthread has been folded into libc.
407 407 * =======================================================
408 408 */
409 409
410 410 /*
411 411 * prt_addr() is called up to three times to generate arguments for
412 412 * one call to mdb_printf(). We must return at least three different
413 413 * pointers to static storage for consecutive calls to prt_addr().
414 414 */
415 415 static const char *
416 416 prt_addr(void *addr, int pad)
417 417 {
418 418 static char buffer[4][24];
419 419 static int ix = 0;
420 420 char *buf;
421 421
422 422 if (ix == 4) /* use buffers in sequence: 0, 1, 2, 3 */
423 423 ix = 0;
424 424 buf = buffer[ix++];
425 425 if (addr == NULL)
426 426 return (pad? "<NULL> " : "<NULL>");
427 427 else {
428 428 #ifdef _LP64
429 429 (void) mdb_snprintf(buf, sizeof (buffer[0]), "0x%016lx", addr);
430 430 if (pad)
431 431 (void) strcpy(buf + 18, " ");
432 432 #else
433 433 (void) mdb_snprintf(buf, sizeof (buffer[0]), "0x%08lx", addr);
434 434 if (pad)
435 435 (void) strcpy(buf + 10, " ");
436 436 #endif /* _LP64 */
437 437 return (buf);
438 438 }
439 439 }
440 440
441 441 #define HD(str) mdb_printf(" " str "\n")
442 442 #define OFFSTR "+0x%-7lx "
443 443 #define OFFSET(member) ((size_t)OFFSETOF(ulwp_t, member))
444 444
445 445 /*ARGSUSED*/
446 446 static int
447 447 d_ulwp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
448 448 {
449 449 ulwp_t ulwp;
450 450
451 451 if (argc != 0 || !(flags & DCMD_ADDRSPEC))
452 452 return (DCMD_USAGE);
453 453
454 454 if (mdb_vread(&ulwp, sizeof (ulwp), addr) != sizeof (ulwp) &&
455 455 (bzero(&ulwp, sizeof (ulwp)),
456 456 mdb_vread(&ulwp, REPLACEMENT_SIZE, addr)) != REPLACEMENT_SIZE) {
457 457 mdb_warn("failed to read ulwp at 0x%p", addr);
458 458 return (DCMD_ERR);
459 459 }
460 460
461 461 mdb_printf("%#a\n", addr);
462 462
463 463 HD("self uberdata");
464 464 mdb_printf(OFFSTR "%s %s\n",
465 465 OFFSET(ul_self),
466 466 prt_addr(ulwp.ul_self, 1),
467 467 prt_addr(ulwp.ul_uberdata, 0));
468 468
469 469 HD("tlsent ntlsent");
470 470 mdb_printf(OFFSTR "%s %ld\n",
471 471 OFFSET(ul_tlsent),
472 472 prt_addr(ulwp.ul_tlsent, 1),
473 473 ulwp.ul_ntlsent);
474 474
475 475 HD("forw back next");
476 476 mdb_printf(OFFSTR "%s %s %s\n",
477 477 OFFSET(ul_forw),
478 478 prt_addr(ulwp.ul_forw, 1),
479 479 prt_addr(ulwp.ul_back, 1),
480 480 prt_addr(ulwp.ul_next, 0));
481 481
482 482 HD("hash rval stk");
483 483 mdb_printf(OFFSTR "%s %s %s\n",
484 484 OFFSET(ul_hash),
485 485 prt_addr(ulwp.ul_hash, 1),
486 486 prt_addr(ulwp.ul_rval, 1),
487 487 prt_addr(ulwp.ul_stk, 0));
488 488
489 489 HD("mapsiz guardsize stktop stksiz");
490 490 mdb_printf(OFFSTR "%-10ld %-10ld %s %ld\n",
491 491 OFFSET(ul_mapsiz),
492 492 ulwp.ul_mapsiz,
493 493 ulwp.ul_guardsize,
494 494 prt_addr((void *)ulwp.ul_stktop, 1),
495 495 ulwp.ul_stksiz);
496 496
497 497 HD("ustack.ss_sp ustack.ss_size ustack.ss_flags");
498 498 mdb_printf(OFFSTR "%s %-21ld %s\n",
499 499 OFFSET(ul_ustack.ss_sp),
500 500 prt_addr(ulwp.ul_ustack.ss_sp, 1),
501 501 ulwp.ul_ustack.ss_size,
502 502 stack_flags(&ulwp.ul_ustack));
503 503
504 504 HD("ix lwpid pri epri policy cid");
505 505 mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n",
506 506 OFFSET(ul_ix),
507 507 ulwp.ul_ix,
508 508 ulwp.ul_lwpid,
509 509 ulwp.ul_pri,
510 510 ulwp.ul_epri,
511 511 ulwp.ul_policy,
512 512 ulwp.ul_cid);
513 513
514 514 HD("cursig pleasestop stop signalled dead unwind");
515 515 mdb_printf(OFFSTR "%-10d ",
516 516 OFFSET(ul_cursig),
517 517 ulwp.ul_cursig);
518 518 mdb_printf(ulwp.ul_pleasestop? "0x%-8x " : "%-10d ",
519 519 ulwp.ul_pleasestop);
520 520 mdb_printf(ulwp.ul_stop? "0x%-8x " : "%-10d ",
521 521 ulwp.ul_stop);
522 522 mdb_printf("%-10d %-10d %d\n",
523 523 ulwp.ul_signalled,
524 524 ulwp.ul_dead,
525 525 ulwp.ul_unwind);
526 526
527 527 HD("detached writer stopping can'prolog preempt savpreempt");
528 528 mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n",
529 529 OFFSET(ul_detached),
530 530 ulwp.ul_detached,
531 531 ulwp.ul_writer,
532 532 ulwp.ul_stopping,
533 533 ulwp.ul_cancel_prologue,
534 534 ulwp.ul_preempt,
535 535 ulwp.ul_savpreempt);
536 536
537 537 HD("sigsuspend main fork primarymap m'spinners d'noreserv");
538 538 mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n",
539 539 OFFSET(ul_sigsuspend),
540 540 ulwp.ul_sigsuspend,
541 541 ulwp.ul_main,
542 542 ulwp.ul_fork,
543 543 ulwp.ul_primarymap,
544 544 ulwp.ul_max_spinners,
545 545 ulwp.ul_door_noreserve);
546 546
547 547 HD("queue_fifo c'w'defer e'detect' async_safe rt rtqueued");
548 548 mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n",
549 549 OFFSET(ul_queue_fifo),
550 550 ulwp.ul_queue_fifo,
551 551 ulwp.ul_cond_wait_defer,
552 552 ulwp.ul_error_detection,
553 553 ulwp.ul_async_safe,
554 554 ulwp.ul_rt,
555 555 ulwp.ul_rtqueued);
556 556
557 557 HD("misaligned adapt'spin queue_spin critical sigdefer vfork");
558 558 mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n",
559 559 OFFSET(ul_misaligned),
560 560 ulwp.ul_misaligned,
561 561 ulwp.ul_adaptive_spin,
562 562 ulwp.ul_queue_spin,
563 563 ulwp.ul_critical,
564 564 ulwp.ul_sigdefer,
565 565 ulwp.ul_vfork);
566 566
567 567 HD("cancelable c'pending c'disabled c'async save_async mutator");
568 568 mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n",
569 569 OFFSET(ul_cancelable),
570 570 ulwp.ul_cancelable,
571 571 ulwp.ul_cancel_pending,
572 572 ulwp.ul_cancel_disabled,
573 573 ulwp.ul_cancel_async,
574 574 ulwp.ul_save_async,
575 575 ulwp.ul_mutator);
576 576
577 577 HD("created replace nocancel errno errnop");
578 578 mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %s\n",
579 579 OFFSET(ul_created),
580 580 ulwp.ul_created,
581 581 ulwp.ul_replace,
582 582 ulwp.ul_nocancel,
583 583 ulwp.ul_errno,
584 584 prt_addr(ulwp.ul_errnop, 0));
585 585
586 586 HD("clnup_hdr schedctl_called schedctl");
587 587 mdb_printf(OFFSTR "%s %s %s\n",
588 588 OFFSET(ul_clnup_hdr),
589 589 prt_addr(ulwp.ul_clnup_hdr, 1),
590 590 prt_addr(ulwp.ul_schedctl_called, 1),
591 591 prt_addr((void *)ulwp.ul_schedctl, 0));
592 592
593 593 HD("bindflags libc_locks stsd &ftsd");
594 594 mdb_printf(OFFSTR,
595 595 OFFSET(ul_bindflags));
596 596 mdb_printf(ulwp.ul_bindflags? "0x%-8x " : "%-10d ",
597 597 ulwp.ul_bindflags);
598 598 mdb_printf("%-10d ", ulwp.ul_libc_locks);
599 599 mdb_printf("%s %s\n",
600 600 prt_addr(ulwp.ul_stsd, 1),
601 601 prt_addr((void *)(addr + OFFSET(ul_ftsd[0])), 0));
602 602
603 603 HD("eventmask[0..1] eventnum eventdata");
604 604 mdb_printf(OFFSTR "0x%08x 0x%08x %-21d %s\n",
605 605 OFFSET(ul_td_evbuf.eventmask.event_bits[0]),
606 606 ulwp.ul_td_evbuf.eventmask.event_bits[0],
607 607 ulwp.ul_td_evbuf.eventmask.event_bits[1],
608 608 ulwp.ul_td_evbuf.eventnum,
609 609 prt_addr(ulwp.ul_td_evbuf.eventdata, 0));
610 610
611 611 HD("td'enable sync'reg qtype cv_wake rtld usropts");
612 612 mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d ",
613 613 OFFSET(ul_td_events_enable),
614 614 ulwp.ul_td_events_enable,
615 615 ulwp.ul_sync_obj_reg,
616 616 ulwp.ul_qtype,
617 617 ulwp.ul_cv_wake,
618 618 ulwp.ul_rtld);
619 619 mdb_printf(ulwp.ul_usropts? "0x%x\n" : "%d\n",
620 620 ulwp.ul_usropts);
621 621
622 622 HD("startpc startarg wchan");
623 623 mdb_printf(OFFSTR "%s %s %s\n",
624 624 OFFSET(ul_startpc),
625 625 prt_addr((void *)ulwp.ul_startpc, 1),
626 626 prt_addr(ulwp.ul_startarg, 1),
627 627 prt_addr(ulwp.ul_wchan, 0));
628 628
629 629 HD("link sleepq cvmutex");
630 630 mdb_printf(OFFSTR "%s %s %s\n",
631 631 OFFSET(ul_link),
632 632 prt_addr(ulwp.ul_link, 1),
633 633 prt_addr(ulwp.ul_sleepq, 1),
634 634 prt_addr(ulwp.ul_cvmutex, 0));
635 635
636 636 HD("mxchain save_state");
637 637 mdb_printf(OFFSTR "%s %d\n",
638 638 OFFSET(ul_mxchain),
639 639 prt_addr(ulwp.ul_mxchain, 1),
640 640 ulwp.ul_save_state);
641 641
642 642 HD("rdlockcnt rd_rwlock rd_count");
643 643 mdb_printf(OFFSTR "%-21d %s %d\n",
644 644 OFFSET(ul_rdlockcnt),
645 645 ulwp.ul_rdlockcnt,
646 646 prt_addr(ulwp.ul_readlock.single.rd_rwlock, 1),
647 647 ulwp.ul_readlock.single.rd_count);
648 648
649 649 HD("heldlockcnt heldlocks tpdp");
650 650 mdb_printf(OFFSTR "%-21d %s %s\n",
651 651 OFFSET(ul_heldlockcnt),
652 652 ulwp.ul_heldlockcnt,
653 653 prt_addr(ulwp.ul_heldlocks.single, 1),
654 654 prt_addr(ulwp.ul_tpdp, 0));
655 655
656 656 HD("siglink s'l'spin s'l'spin2 s'l'sleep s'l'wakeup");
657 657 mdb_printf(OFFSTR "%s %-10d %-10d %-10d %d\n",
658 658 OFFSET(ul_siglink),
659 659 prt_addr(ulwp.ul_siglink, 1),
660 660 ulwp.ul_spin_lock_spin,
661 661 ulwp.ul_spin_lock_spin2,
662 662 ulwp.ul_spin_lock_sleep,
663 663 ulwp.ul_spin_lock_wakeup);
664 664
665 665 HD("&queue_root rtclassid pilocks");
666 666 mdb_printf(OFFSTR "%s %-10d %d\n",
667 667 OFFSET(ul_queue_root),
668 668 prt_addr((void *)(addr + OFFSET(ul_queue_root)), 1),
669 669 ulwp.ul_rtclassid,
670 670 ulwp.ul_pilocks);
671 671
672 672 /*
673 673 * The remainder of the ulwp_t structure
674 674 * is invalid if this is a replacement.
675 675 */
676 676 if (ulwp.ul_replace)
677 677 return (DCMD_OK);
678 678
679 679 HD("sigmask[0..3]");
680 680 mdb_printf(OFFSTR "0x%08x 0x%08x 0x%08x 0x%08x\n",
681 681 OFFSET(ul_sigmask.__sigbits[0]),
682 682 ulwp.ul_sigmask.__sigbits[0],
683 683 ulwp.ul_sigmask.__sigbits[1],
684 684 ulwp.ul_sigmask.__sigbits[2],
685 685 ulwp.ul_sigmask.__sigbits[3]);
686 686
687 687 HD("tmpmask[0..3]");
688 688 mdb_printf(OFFSTR "0x%08x 0x%08x 0x%08x 0x%08x\n",
689 689 OFFSET(ul_tmpmask.__sigbits[0]),
690 690 ulwp.ul_tmpmask.__sigbits[0],
691 691 ulwp.ul_tmpmask.__sigbits[1],
692 692 ulwp.ul_tmpmask.__sigbits[2],
693 693 ulwp.ul_tmpmask.__sigbits[3]);
694 694
695 695 HD("&siginfo &spinlock &fpuenv");
696 696 mdb_printf(OFFSTR "%s %s %s\n",
697 697 OFFSET(ul_siginfo),
698 698 prt_addr((void *)(addr + OFFSET(ul_siginfo)), 1),
699 699 prt_addr((void *)(addr + OFFSET(ul_spinlock)), 1),
700 700 prt_addr((void *)(addr + OFFSET(ul_fpuenv)), 0));
701 701
702 702 HD("tmem.size &tmem.roots");
703 703 mdb_printf(OFFSTR "%-21H %s\n",
704 704 OFFSET(ul_tmem),
705 705 ulwp.ul_tmem.tm_size,
706 706 prt_addr((void *)(addr + OFFSET(ul_tmem) + sizeof (size_t)), 0));
707 707
708 708 return (DCMD_OK);
709 709 }
710 710
711 711 /*
712 712 * Get the address of the unique uberdata_t structure.
713 713 */
714 714 static uintptr_t
715 715 uberdata_addr(void)
716 716 {
717 717 uintptr_t uaddr;
718 718 uintptr_t addr;
719 719 GElf_Sym sym;
720 720
721 721 if (mdb_lookup_by_obj("libc.so.1", "_tdb_bootstrap", &sym) != 0) {
722 722 mdb_warn("cannot find libc.so.1`_tdb_bootstrap");
723 723 return (NULL);
724 724 }
725 725 if (mdb_vread(&addr, sizeof (addr), sym.st_value) == sizeof (addr) &&
726 726 addr != NULL &&
727 727 mdb_vread(&uaddr, sizeof (uaddr), addr) == sizeof (uaddr) &&
728 728 uaddr != NULL) {
729 729 return (uaddr);
730 730 }
731 731 if (mdb_lookup_by_obj("libc.so.1", "_uberdata", &sym) != 0) {
732 732 mdb_warn("cannot find libc.so.1`_uberdata");
733 733 return (NULL);
734 734 }
735 735 return ((uintptr_t)sym.st_value);
736 736 }
737 737
738 738 #undef OFFSET
739 739 #define OFFSET(member) ((size_t)OFFSETOF(uberdata_t, member))
740 740
741 741 /*ARGSUSED*/
742 742 static int
743 743 d_uberdata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
744 744 {
745 745 uberdata_t uberdata;
746 746 int i;
747 747
748 748 if (argc != 0)
749 749 return (DCMD_USAGE);
750 750 if (!(flags & DCMD_ADDRSPEC) && (addr = uberdata_addr()) == NULL)
751 751 return (DCMD_ERR);
752 752
753 753 if (mdb_vread(&uberdata, sizeof (uberdata), addr) !=
754 754 sizeof (uberdata)) {
755 755 mdb_warn("failed to read uberdata at 0x%p", addr);
756 756 return (DCMD_ERR);
757 757 }
758 758
759 759 mdb_printf("%#a\n", addr);
760 760
761 761 HD("&link_lock &ld_lock &fork_lock");
762 762 mdb_printf(OFFSTR "%s %s %s\n",
763 763 OFFSET(link_lock),
764 764 prt_addr((void *)(addr + OFFSET(link_lock)), 1),
765 765 prt_addr((void *)(addr + OFFSET(ld_lock)), 1),
766 766 prt_addr((void *)(addr + OFFSET(fork_lock)), 0));
767 767
768 768 HD("&atfork_lock &callout_lock &tdb_hash_lock");
769 769 mdb_printf(OFFSTR "%s %s %s\n",
770 770 OFFSET(atfork_lock),
771 771 prt_addr((void *)(addr + OFFSET(atfork_lock)), 1),
772 772 prt_addr((void *)(addr + OFFSET(callout_lock)), 1),
773 773 prt_addr((void *)(addr + OFFSET(tdb_hash_lock)), 0));
774 774
775 775 HD("&tdb_hash_lock_stats &siguaction[0]");
776 776 mdb_printf(OFFSTR "%s %s\n",
777 777 OFFSET(tdb_hash_lock_stats),
778 778 prt_addr((void *)(addr + OFFSET(tdb_hash_lock_stats)), 1),
779 779 prt_addr((void *)(addr + OFFSET(siguaction)), 0));
780 780
781 781 HD("&bucket free_list chunks");
782 782 for (i = 0; i < NBUCKETS; i++) {
783 783 mdb_printf(OFFSTR "%s %s %ld\n",
784 784 OFFSET(bucket[i]),
785 785 prt_addr((void *)(addr + OFFSET(bucket[i])), 1),
786 786 prt_addr(uberdata.bucket[i].free_list, 1),
787 787 uberdata.bucket[i].chunks);
788 788 }
789 789
790 790 HD("&atexit_root head exit_frame_monitor");
791 791 mdb_printf(OFFSTR "%s %s %s\n",
792 792 OFFSET(atexit_root),
793 793 prt_addr((void *)(addr + OFFSET(atexit_root.exitfns_lock)), 1),
794 794 prt_addr(uberdata.atexit_root.head, 1),
795 795 prt_addr(uberdata.atexit_root.exit_frame_monitor, 0));
796 796
797 797 HD("&quickexit_root head");
798 798 mdb_printf(OFFSTR "%s %s\n",
799 799 OFFSET(quickexit_root),
800 800 prt_addr((void *)(addr + OFFSET(quickexit_root.exitfns_lock)), 1),
801 801 prt_addr(uberdata.quickexit_root.head, 0));
802 802
803 803
804 804 HD("&tsd_metadata tsdm_nkeys tsdm_nused tsdm_destro");
805 805 mdb_printf(OFFSTR "%s %-10d %-10d %s\n",
806 806 OFFSET(tsd_metadata),
807 807 prt_addr((void *)(addr + OFFSET(tsd_metadata.tsdm_lock)), 1),
808 808 uberdata.tsd_metadata.tsdm_nkeys,
809 809 uberdata.tsd_metadata.tsdm_nused,
810 810 prt_addr((void *)uberdata.tsd_metadata.tsdm_destro, 0));
811 811
812 812 HD("&tls_metadata tls_modinfo.data tls_modinfo.size");
813 813 mdb_printf(OFFSTR "%s %s %ld\n",
814 814 OFFSET(tls_metadata),
815 815 prt_addr((void *)(addr + OFFSET(tls_metadata.tls_lock)), 1),
816 816 prt_addr(uberdata.tls_metadata.tls_modinfo.tls_data, 1),
817 817 uberdata.tls_metadata.tls_modinfo.tls_size);
818 818
819 819 HD(" static_tls.data static_tls.size");
820 820 mdb_printf(OFFSTR "%s %s %ld\n",
821 821 OFFSET(tls_metadata.static_tls),
822 822 " ",
823 823 prt_addr(uberdata.tls_metadata.static_tls.tls_data, 1),
824 824 uberdata.tls_metadata.static_tls.tls_size);
825 825
826 826 HD("primary_ma bucket_ini uflags.mt uflags.pad uflags.trs uflags.ted");
827 827 mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n",
828 828 OFFSET(primary_map),
829 829 uberdata.primary_map,
830 830 uberdata.bucket_init,
831 831 uberdata.uberflags.uf_x.x_mt,
832 832 uberdata.uberflags.uf_x.x_pad,
833 833 uberdata.uberflags.uf_x.x_tdb_register_sync,
834 834 uberdata.uberflags.uf_x.x_thread_error_detection);
835 835
836 836 HD("queue_head thr_hash_table hash_size hash_mask");
837 837 mdb_printf(OFFSTR "%s %s %-10d 0x%x\n",
838 838 OFFSET(queue_head),
839 839 prt_addr(uberdata.queue_head, 1),
840 840 prt_addr(uberdata.thr_hash_table, 1),
841 841 uberdata.hash_size,
842 842 uberdata.hash_mask);
843 843
844 844 HD("ulwp_one all_lwps all_zombies");
845 845 mdb_printf(OFFSTR "%s %s %s\n",
846 846 OFFSET(ulwp_one),
847 847 prt_addr(uberdata.ulwp_one, 1),
848 848 prt_addr(uberdata.all_lwps, 1),
849 849 prt_addr(uberdata.all_zombies, 0));
850 850
851 851 HD("nthreads nzombies ndaemons pid");
852 852 mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d\n",
853 853 OFFSET(nthreads),
854 854 uberdata.nthreads,
855 855 uberdata.nzombies,
856 856 uberdata.ndaemons,
857 857 (int)uberdata.pid);
858 858
859 859 HD("sigacthandler setctxt");
860 860 mdb_printf(OFFSTR "%s %s\n",
861 861 OFFSET(sigacthandler),
862 862 prt_addr((void *)uberdata.sigacthandler, 1),
863 863 prt_addr((void *)uberdata.setctxt, 1));
864 864
865 865 HD("lwp_stacks lwp_laststack nfreestack stk_cache");
866 866 mdb_printf(OFFSTR "%s %s %-10d %d\n",
867 867 OFFSET(lwp_stacks),
868 868 prt_addr(uberdata.lwp_stacks, 1),
869 869 prt_addr(uberdata.lwp_laststack, 1),
870 870 uberdata.nfreestack,
871 871 uberdata.thread_stack_cache);
872 872
873 873 HD("ulwp_freelist ulwp_lastfree ulwp_replace_free");
874 874 mdb_printf(OFFSTR "%s %s %s\n",
875 875 OFFSET(ulwp_freelist),
876 876 prt_addr(uberdata.ulwp_freelist, 1),
877 877 prt_addr(uberdata.ulwp_lastfree, 1),
878 878 prt_addr(uberdata.ulwp_replace_free, 0));
879 879
880 880 HD("ulwp_replace_last atforklist");
881 881 mdb_printf(OFFSTR "%s %s\n",
882 882 OFFSET(ulwp_replace_last),
883 883 prt_addr(uberdata.ulwp_replace_last, 1),
884 884 prt_addr(uberdata.atforklist, 0));
885 885
886 886 HD("robustlocks robustlist");
887 887 mdb_printf(OFFSTR "%s %s\n",
888 888 OFFSET(robustlocks),
889 889 prt_addr(uberdata.robustlocks, 1),
890 890 prt_addr(uberdata.robustlist, 1));
891 891
892 892 HD("progname ub_broot");
893 893 mdb_printf(OFFSTR "%s %s\n",
894 894 OFFSET(progname),
895 895 prt_addr(uberdata.progname, 1),
896 896 prt_addr(uberdata.ub_broot, 1));
897 897
898 898 HD("tdb_bootstrap tdb_sync_addr_hash tdb_'count tdb_'fail");
899 899 mdb_printf(OFFSTR "%s %s %-10d %d\n",
900 900 OFFSET(tdb_bootstrap),
901 901 prt_addr(uberdata.tdb_bootstrap, 1),
902 902 prt_addr(uberdata.tdb.tdb_sync_addr_hash, 1),
903 903 uberdata.tdb.tdb_register_count,
904 904 uberdata.tdb.tdb_hash_alloc_failed);
905 905
906 906 HD("tdb_sync_addr_free tdb_sync_addr_last tdb_sync_alloc");
907 907 mdb_printf(OFFSTR "%s %s %ld\n",
908 908 OFFSET(tdb.tdb_sync_addr_free),
909 909 prt_addr(uberdata.tdb.tdb_sync_addr_free, 1),
910 910 prt_addr(uberdata.tdb.tdb_sync_addr_last, 1),
911 911 uberdata.tdb.tdb_sync_alloc);
912 912
913 913 HD("tdb_ev_global_mask tdb_events");
914 914 mdb_printf(OFFSTR "0x%08x 0x%08x %s\n",
915 915 OFFSET(tdb.tdb_ev_global_mask),
916 916 uberdata.tdb.tdb_ev_global_mask.event_bits[0],
917 917 uberdata.tdb.tdb_ev_global_mask.event_bits[1],
918 918 prt_addr((void *)uberdata.tdb.tdb_events, 0));
919 919
920 920 return (DCMD_OK);
921 921 }
922 922
923 923 static int
924 924 ulwp_walk_init(mdb_walk_state_t *wsp)
925 925 {
926 926 uintptr_t addr = wsp->walk_addr;
927 927 uintptr_t uber_addr;
928 928
929 929 if (addr == NULL &&
930 930 ((uber_addr = uberdata_addr()) == NULL ||
931 931 mdb_vread(&addr, sizeof (addr),
932 932 uber_addr + OFFSETOF(uberdata_t, all_lwps))
933 933 != sizeof (addr))) {
934 934 mdb_warn("cannot find 'uberdata.all_lwps'");
935 935 return (WALK_ERR);
936 936 }
937 937 if (addr == NULL)
938 938 return (WALK_DONE);
939 939 wsp->walk_addr = addr;
940 940 wsp->walk_data = (void *)addr;
941 941 return (WALK_NEXT);
942 942 }
943 943
944 944 static int
945 945 ulwp_walk_step(mdb_walk_state_t *wsp)
946 946 {
947 947 uintptr_t addr = wsp->walk_addr;
948 948 ulwp_t ulwp;
949 949
950 950 if (addr == NULL)
951 951 return (WALK_DONE);
952 952 if (mdb_vread(&ulwp, sizeof (ulwp), addr) != sizeof (ulwp) &&
953 953 (bzero(&ulwp, sizeof (ulwp)),
954 954 mdb_vread(&ulwp, REPLACEMENT_SIZE, addr)) != REPLACEMENT_SIZE) {
955 955 mdb_warn("failed to read ulwp at 0x%p", addr);
956 956 return (WALK_ERR);
957 957 }
958 958 /*
959 959 * If we have looped around to the beginning
960 960 * of the circular linked list, we are done.
961 961 */
962 962 if ((wsp->walk_addr = (uintptr_t)ulwp.ul_forw)
963 963 == (uintptr_t)wsp->walk_data)
964 964 wsp->walk_addr = NULL;
965 965 return (wsp->walk_callback(addr, &ulwp, wsp->walk_cbdata));
966 966 }
967 967
968 968 /* Avoid classifying NULL pointers as part of the main stack on x86 */
969 969 #define MIN_STACK_ADDR (0x10000ul)
970 970
971 971 static int
972 972 whatis_walk_ulwp(uintptr_t addr, const ulwp_t *ulwp, mdb_whatis_t *w)
973 973 {
974 974 uintptr_t cur;
975 975 lwpid_t id = ulwp->ul_lwpid;
976 976 uintptr_t top, base, size;
977 977
978 978 while (mdb_whatis_match(w, addr, sizeof (ulwp_t), &cur))
979 979 mdb_whatis_report_object(w, cur, addr,
980 980 "allocated as thread %#r's ulwp_t\n", id);
981 981
982 982 top = (uintptr_t)ulwp->ul_stktop;
983 983 size = ulwp->ul_stksiz;
984 984
985 985 /*
986 986 * The main stack ends up being a little weird, especially if
987 987 * the stack ulimit is unlimited. This tries to take that into
988 988 * account.
989 989 */
990 990 if (size > top)
991 991 size = top;
992 992 if (top > MIN_STACK_ADDR && top - size < MIN_STACK_ADDR)
993 993 size = top - MIN_STACK_ADDR;
994 994
995 995 base = top - size;
996 996
997 997 while (mdb_whatis_match(w, base, size, &cur))
998 998 mdb_whatis_report_address(w, cur, "in [ stack tid=%#r ]\n", id);
999 999
1000 1000 if (ulwp->ul_ustack.ss_flags & SS_ONSTACK) {
1001 1001 base = (uintptr_t)ulwp->ul_ustack.ss_sp;
1002 1002 size = ulwp->ul_ustack.ss_size;
1003 1003
1004 1004 while (mdb_whatis_match(w, base, size, &cur))
1005 1005 mdb_whatis_report_address(w, cur,
1006 1006 "in [ altstack tid=%#r ]\n", id);
1007 1007 }
1008 1008
1009 1009 return (WHATIS_WALKRET(w));
1010 1010 }
1011 1011
1012 1012 /*ARGSUSED*/
1013 1013 static int
1014 1014 whatis_run_ulwps(mdb_whatis_t *w, void *arg)
1015 1015 {
1016 1016 if (mdb_walk("ulwps", (mdb_walk_cb_t)whatis_walk_ulwp, w) == -1) {
1017 1017 mdb_warn("couldn't find ulwps walker");
1018 1018 return (1);
1019 1019 }
1020 1020 return (0);
1021 1021 }
1022 1022
1023 1023 /*
1024 1024 * =======================================================
1025 1025 * End of thread (previously libthread) interfaces.
1026 1026 * ==================== threads ==========================
1027 1027 */
1028 1028
1029 1029 int
1030 1030 stacks_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1031 1031 {
1032 1032 int rval = stacks(addr, flags, argc, argv);
1033 1033
1034 1034 /*
1035 1035 * For the user-level variant of ::stacks, we don't bother caching
1036 1036 * state, as even a very large program is unlikely to compare to the
1037 1037 * kernel in terms of number of threads. (And if you find yourself
1038 1038 * here in anger, frustrated about how long ::stacks is running on
1039 1039 * your galactically complicated zillion-thread program, hopefully
1040 1040 * you will find some solace in the irony. Okay, probably not...)
1041 1041 */
1042 1042 stacks_cleanup(B_TRUE);
1043 1043 return (rval);
1044 1044 }
1045 1045
1046 1046 typedef struct tid2ulwp_walk {
1047 1047 lwpid_t t2u_tid;
1048 1048 uintptr_t t2u_lwp;
1049 1049 boolean_t t2u_found;
1050 1050 } tid2ulwp_walk_t;
1051 1051
1052 1052 /*ARGSUSED*/
1053 1053 static int
1054 1054 tid2ulwp_walk(uintptr_t addr, ulwp_t *ulwp, tid2ulwp_walk_t *t2u)
1055 1055 {
1056 1056 if (ulwp->ul_lwpid == t2u->t2u_tid) {
1057 1057 t2u->t2u_lwp = addr;
1058 1058 t2u->t2u_found = B_TRUE;
1059 1059 return (WALK_DONE);
1060 1060 }
1061 1061
1062 1062 return (WALK_NEXT);
1063 1063 }
1064 1064
1065 1065 static int
1066 1066 tid2ulwp_impl(uintptr_t tid_addr, uintptr_t *ulwp_addrp)
1067 1067 {
1068 1068 tid2ulwp_walk_t t2u;
1069 1069
1070 1070 bzero(&t2u, sizeof (t2u));
1071 1071 t2u.t2u_tid = (lwpid_t)tid_addr;
1072 1072
1073 1073 if (mdb_walk("ulwp", (mdb_walk_cb_t)tid2ulwp_walk, &t2u) != 0) {
1074 1074 mdb_warn("can't walk 'ulwp'");
1075 1075 return (DCMD_ERR);
1076 1076 }
1077 1077
1078 1078 if (!t2u.t2u_found) {
1079 1079 mdb_warn("thread ID %d not found", t2u.t2u_tid);
1080 1080 return (DCMD_ERR);
1081 1081 }
1082 1082 *ulwp_addrp = t2u.t2u_lwp;
1083 1083 return (DCMD_OK);
1084 1084 }
1085 1085
1086 1086 /*ARGSUSED*/
1087 1087 static int
1088 1088 tid2ulwp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1089 1089 {
1090 1090 uintptr_t ulwp_addr;
1091 1091 int error;
1092 1092
1093 1093 if (argc != 0)
1094 1094 return (DCMD_USAGE);
1095 1095
1096 1096 error = tid2ulwp_impl(addr, &ulwp_addr);
1097 1097 if (error == DCMD_OK)
1098 1098 mdb_printf("%p\n", ulwp_addr);
1099 1099 return (error);
1100 1100 }
1101 1101
1102 1102 typedef struct mdb_libc_ulwp {
1103 1103 void *ul_ftsd[TSD_NFAST];
1104 1104 tsd_t *ul_stsd;
1105 1105 } mdb_libc_ulwp_t;
1106 1106
1107 1107 /*
1108 1108 * Map from thread pointer to tsd for given key
1109 1109 */
1110 1110 static int
1111 1111 d_tsd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1112 1112 {
1113 1113 mdb_libc_ulwp_t u;
1114 1114 uintptr_t ulwp_addr;
1115 1115 uintptr_t key = NULL;
1116 1116 void *element = NULL;
1117 1117
1118 1118 if (mdb_getopts(argc, argv, 'k', MDB_OPT_UINTPTR, &key, NULL) != argc)
1119 1119 return (DCMD_USAGE);
1120 1120
1121 1121 if (!(flags & DCMD_ADDRSPEC) || key == NULL)
1122 1122 return (DCMD_USAGE);
1123 1123
1124 1124 if (tid2ulwp_impl(addr, &ulwp_addr) != DCMD_OK)
1125 1125 return (DCMD_ERR);
1126 1126
1127 1127 if (mdb_ctf_vread(&u, "ulwp_t", "mdb_libc_ulwp_t", ulwp_addr, 0) == -1)
1128 1128 return (DCMD_ERR);
1129 1129
1130 1130 if (key < TSD_NFAST) {
1131 1131 element = u.ul_ftsd[key];
1132 1132 } else if (u.ul_stsd != NULL) {
1133 1133 uint_t nalloc;
1134 1134 /* tsd_t is a union, so we can't use ctf_vread() on it. */
1135 1135 if (mdb_vread(&nalloc, sizeof (nalloc),
1136 1136 (uintptr_t)&u.ul_stsd->tsd_nalloc) == -1) {
1137 1137 mdb_warn("failed to read tsd_t at %p", u.ul_stsd);
1138 1138 return (DCMD_ERR);
1139 1139 }
1140 1140 if (key < nalloc) {
1141 1141 if (mdb_vread(&element, sizeof (element),
1142 1142 (uintptr_t)&u.ul_stsd->tsd_data[key]) == -1) {
1143 1143 mdb_warn("failed to read tsd_t at %p",
1144 1144 u.ul_stsd);
1145 1145 return (DCMD_ERR);
1146 1146 }
1147 1147 }
1148 1148 }
1149 1149
1150 1150 if (element == NULL && (flags & DCMD_PIPE))
1151 1151 return (DCMD_OK);
1152 1152
1153 1153 mdb_printf("%p\n", element);
1154 1154 return (DCMD_OK);
1155 1155 }
1156 1156
1157 1157 static const mdb_dcmd_t dcmds[] = {
1158 1158 { "jmp_buf", ":", "print jmp_buf contents", d_jmp_buf, NULL },
1159 1159 { "sigjmp_buf", ":", "print sigjmp_buf contents", d_sigjmp_buf, NULL },
1160 1160 { "siginfo", ":", "print siginfo_t structure", d_siginfo, NULL },
1161 1161 { "stacks", "?[-afiv] [-c func] [-C func] [-m module] [-M module] ",
1162 1162 "print unique thread stacks", stacks_dcmd, stacks_help },
1163 1163 { "tid2ulwp", "?", "convert TID to ulwp_t address", tid2ulwp },
1164 1164 { "ucontext", ":", "print ucontext_t structure", d_ucontext, NULL },
1165 1165 { "ulwp", ":", "print ulwp_t structure", d_ulwp, NULL },
1166 1166 { "uberdata", ":", "print uberdata_t structure", d_uberdata, NULL },
1167 1167 { "tsd", ":-k key", "print tsd for this thread", d_tsd, NULL },
1168 1168 { NULL }
1169 1169 };
1170 1170
1171 1171 static const mdb_walker_t walkers[] = {
1172 1172 { "ucontext", "walk ucontext_t uc_link list",
1173 1173 NULL, uc_walk_step, NULL, NULL },
1174 1174 { "oldcontext", "walk per-lwp oldcontext pointers",
1175 1175 oldc_walk_init, oldc_walk_step, oldc_walk_fini, NULL },
1176 1176 { "ulwps", "walk list of ulwp_t pointers",
1177 1177 ulwp_walk_init, ulwp_walk_step, NULL, NULL },
1178 1178 { "ulwp", "walk list of ulwp_t pointers",
1179 1179 ulwp_walk_init, ulwp_walk_step, NULL, NULL },
1180 1180 { NULL }
1181 1181 };
1182 1182
1183 1183 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
1184 1184
1185 1185 const mdb_modinfo_t *
1186 1186 _mdb_init(void)
1187 1187 {
1188 1188 mdb_whatis_register("threads", whatis_run_ulwps, NULL,
1189 1189 WHATIS_PRIO_EARLY, WHATIS_REG_NO_ID);
1190 1190
1191 1191 return (&modinfo);
1192 1192 }
|
↓ open down ↓ |
1192 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX