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