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.
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.
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]
23 * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2012 by Delphix. All rights reserved.
25 * Copyright 2017, Joyent, Inc.
28 #include <sys/mdb_modapi.h>
29 #include <mdb/mdb_whatis.h>
30 #include <mdb/mdb_ctf.h>
37 #include <thr_uberdata.h>
38 #include "findstack.h"
41 stack_flags(const stack_t
*sp
)
45 if (sp
->ss_flags
== 0)
46 (void) strcpy(buf
, " 0");
47 else if (sp
->ss_flags
& ~(SS_ONSTACK
| SS_DISABLE
))
48 (void) mdb_snprintf(buf
, sizeof (buf
), " 0x%x", sp
->ss_flags
);
51 if (sp
->ss_flags
& SS_ONSTACK
)
52 (void) strcat(buf
, "|ONSTACK");
53 if (sp
->ss_flags
& SS_DISABLE
)
54 (void) strcat(buf
, "|DISABLE");
62 d_jmp_buf(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
65 const ulong_t
*b
= (const ulong_t
*)jb
;
70 if (mdb_vread(&jb
, sizeof (jb
), addr
) != sizeof (jb
)) {
71 mdb_warn("failed to read jmp_buf at %p", addr
);
76 mdb_printf(" %%sp = 0x%lx\n", b
[1]);
77 mdb_printf(" %%pc = 0x%lx %lA\n", b
[2], b
[2]);
78 mdb_printf(" %%fp = 0x%lx\n", b
[3]);
79 mdb_printf(" %%i7 = 0x%lx %lA\n", b
[4], b
[4]);
80 #elif defined(__amd64)
81 mdb_printf(" %%rbx = 0x%lx\n", b
[0]);
82 mdb_printf(" %%r12 = 0x%lx\n", b
[1]);
83 mdb_printf(" %%r13 = 0x%lx\n", b
[2]);
84 mdb_printf(" %%r14 = 0x%lx\n", b
[3]);
85 mdb_printf(" %%r15 = 0x%lx\n", b
[4]);
86 mdb_printf(" %%rbp = 0x%lx\n", b
[5]);
87 mdb_printf(" %%rsp = 0x%lx\n", b
[6]);
88 mdb_printf(" %%rip = 0x%lx %lA\n", b
[7], b
[7]);
90 mdb_printf(" %%ebx = 0x%lx\n", b
[0]);
91 mdb_printf(" %%esi = 0x%lx\n", b
[1]);
92 mdb_printf(" %%edi = 0x%lx\n", b
[2]);
93 mdb_printf(" %%ebp = 0x%lx\n", b
[3]);
94 mdb_printf(" %%esp = 0x%lx\n", b
[4]);
95 mdb_printf(" %%eip = 0x%lx %lA\n", b
[5], b
[5]);
100 const mdb_bitmask_t uc_flags_bits
[] = {
101 { "UC_SIGMASK", UC_SIGMASK
, UC_SIGMASK
},
102 { "UC_STACK", UC_STACK
, UC_STACK
},
103 { "UC_CPU", UC_CPU
, UC_CPU
},
104 { "UC_FPU", UC_FPU
, UC_FPU
},
106 { "UC_INTR", UC_INTR
, UC_INTR
},
109 { "UC_ASR", UC_ASR
, UC_ASR
},
116 d_ucontext(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
123 if (mdb_vread(&uc
, sizeof (uc
), addr
) != sizeof (uc
)) {
124 mdb_warn("failed to read ucontext at %p", addr
);
128 mdb_printf(" flags = 0x%lx <%b>\n", uc
.uc_flags
,
129 (uint_t
)uc
.uc_flags
, uc_flags_bits
);
130 mdb_printf(" link = 0x%p\n", uc
.uc_link
);
131 mdb_printf(" sigmask = 0x%08x 0x%08x 0x%08x 0x%08x\n",
132 uc
.uc_sigmask
.__sigbits
[0], uc
.uc_sigmask
.__sigbits
[1],
133 uc
.uc_sigmask
.__sigbits
[2], uc
.uc_sigmask
.__sigbits
[3]);
134 mdb_printf(" stack = sp 0x%p size 0x%lx flags %s\n",
135 uc
.uc_stack
.ss_sp
, uc
.uc_stack
.ss_size
, stack_flags(&uc
.uc_stack
));
136 mdb_printf(" mcontext = 0x%p\n",
137 addr
+ OFFSETOF(ucontext_t
, uc_mcontext
));
144 d_sigjmp_buf(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
153 ucontext_t
*sjs_uclink
;
154 ulong_t sjs_pad
[_JBLEN
- 6];
155 sigset_t sjs_sigmask
;
166 if (mdb_vread(&s
, sizeof (s
), addr
) != sizeof (s
)) {
167 mdb_warn("failed to read sigjmp_buf at %p", addr
);
171 mdb_printf(" flags = 0x%x\n", s
.sjs_flags
);
172 mdb_printf(" %%sp = 0x%lx %lA\n", s
.sjs_sp
, s
.sjs_sp
);
173 mdb_printf(" %%pc = 0x%lx %lA\n", s
.sjs_pc
, s
.sjs_pc
);
174 mdb_printf(" %%fp = 0x%lx %lA\n", s
.sjs_fp
, s
.sjs_fp
);
175 mdb_printf(" %%i7 = 0x%lx %lA\n", s
.sjs_i7
, s
.sjs_i7
);
176 mdb_printf(" uclink = %p\n", s
.sjs_uclink
);
177 mdb_printf(" sigset = 0x%08x 0x%08x 0x%08x 0x%08x\n",
178 s
.sjs_sigmask
.__sigbits
[0], s
.sjs_sigmask
.__sigbits
[1],
179 s
.sjs_sigmask
.__sigbits
[2], s
.sjs_sigmask
.__sigbits
[3]);
181 mdb_printf(" %%asi = 0x%lx\n", s
.sjs_asi
);
182 mdb_printf(" %%fprs = 0x%lx\n", s
.sjs_fprs
);
184 mdb_printf(" stack = sp 0x%p size 0x%lx flags %s\n",
185 s
.sjs_stack
.ss_sp
, s
.sjs_stack
.ss_size
, stack_flags(&s
.sjs_stack
));
189 #elif defined(__i386) || defined(__amd64)
190 return (d_ucontext(addr
, flags
, argc
, argv
));
196 d_siginfo(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
198 static const char *const msname
[] = {
199 "USER", "SYSTEM", "TRAP", "TFAULT", "DFAULT", "KFAULT",
200 "USER_LOCK", "SLEEP", "WAIT_CPU", "STOPPED"
203 char signame
[SIG2STR_MAX
];
210 if (mdb_vread(&si
, sizeof (si
), addr
) != sizeof (si
)) {
211 mdb_warn("failed to read siginfo at %p", addr
);
215 if (sig2str(si
.si_signo
, signame
) == -1)
216 (void) strcpy(signame
, "unknown");
218 mdb_printf(" signal %5d (%s)\n", si
.si_signo
, signame
);
219 mdb_printf(" code %5d (", si
.si_code
);
221 switch (si
.si_code
) {
223 mdb_printf("no info");
226 mdb_printf("from DTrace raise() action");
229 mdb_printf("from rctl action");
232 mdb_printf("user generated via kill");
235 mdb_printf("user generated via lwp_kill");
238 mdb_printf("user generated via sigqueue");
241 mdb_printf("from timer expiration");
244 mdb_printf("from async i/o completion");
247 mdb_printf("from message arrival");
250 if (SI_FROMUSER(&si
))
251 mdb_printf("from user process");
253 mdb_printf("from kernel");
256 mdb_printf(")\n errno %5d (%s)\n",
257 si
.si_errno
, strerror(si
.si_errno
));
259 if (si
.si_code
== SI_USER
|| si
.si_code
== SI_QUEUE
) {
260 mdb_printf(" signal sent from PID %d (uid %d)\n",
261 si
.si_pid
, si
.si_uid
);
264 if (si
.si_code
== SI_QUEUE
) {
265 mdb_printf(" signal value = 0t%d / %p\n",
266 si
.si_value
.sival_int
, si
.si_value
.sival_ptr
);
269 switch (si
.si_signo
) {
271 mdb_printf(" signal sent from child PID %d (uid %d)\n",
272 si
.si_pid
, si
.si_uid
);
273 mdb_printf(" usr time = 0t%ld ticks, sys time = 0t%ld ticks\n",
274 si
.si_utime
, si
.si_stime
);
275 mdb_printf(" wait status = 0x%x\n", si
.si_status
);
283 mdb_printf(" fault address = 0x%p\n trapno = %d\n",
284 si
.si_addr
, si
.si_trapno
);
285 mdb_printf(" instruction address = 0x%p %lA\n",
291 mdb_printf(" fd = %d band = 0x%lx\n",
292 si
.si_fd
, si
.si_band
);
296 mdb_printf(" last fault address = 0x%p fault type = %d\n",
297 si
.si_faddr
, si
.si_fault
);
298 mdb_printf(" timestamp = 0t%ld sec 0t%ld nsec\n",
299 si
.si_tstamp
.tv_sec
, si
.si_tstamp
.tv_nsec
);
301 if (si
.__data
.__prof
.__syscall
!= 0) {
302 mdb_printf(" system call %d (", si
.si_syscall
);
303 if (si
.si_nsysarg
> 0) {
304 mdb_printf("%lx", si
.si_sysarg
[0]);
305 for (i
= 1; i
< si
.si_nsysarg
; i
++)
306 mdb_printf(", %lx", si
.si_sysarg
[i
]);
311 for (i
= 0; i
< sizeof (msname
) / sizeof (msname
[0]); i
++) {
312 mdb_printf(" mstate[\"%s\"] = %d\n",
313 msname
[i
], si
.si_mstate
[i
]);
322 uc_walk_step(mdb_walk_state_t
*wsp
)
324 uintptr_t addr
= wsp
->walk_addr
;
327 if (addr
== (uintptr_t)NULL
)
330 if (mdb_vread(&uc
, sizeof (uc
), addr
) != sizeof (uc
)) {
331 mdb_warn("failed to read ucontext at %p", addr
);
335 wsp
->walk_addr
= (uintptr_t)uc
.uc_link
;
336 return (wsp
->walk_callback(addr
, &uc
, wsp
->walk_cbdata
));
340 oldc_walk_init(mdb_walk_state_t
*wsp
)
342 ssize_t nbytes
= mdb_get_xdata("lwpstatus", NULL
, 0);
345 mdb_warn("lwpstatus information not available");
349 if (wsp
->walk_addr
!= (uintptr_t)NULL
) {
350 mdb_warn("walker only supports global walk\n");
354 wsp
->walk_addr
= nbytes
; /* Use walk_addr to track size */
355 wsp
->walk_data
= mdb_alloc(nbytes
, UM_SLEEP
);
357 if (mdb_get_xdata("lwpstatus", wsp
->walk_data
, nbytes
) != nbytes
) {
358 mdb_warn("failed to read lwpstatus information");
359 mdb_free(wsp
->walk_data
, nbytes
);
363 wsp
->walk_arg
= wsp
->walk_data
; /* Use walk_arg to track pointer */
368 oldc_walk_step(mdb_walk_state_t
*wsp
)
370 const lwpstatus_t
*lsp
, *end
;
372 end
= (const lwpstatus_t
*)((uintptr_t)wsp
->walk_data
+ wsp
->walk_addr
);
375 wsp
->walk_arg
= (void *)(lsp
+ 1);
378 uintptr_t addr
= lsp
->pr_oldcontext
;
381 if (addr
== (uintptr_t)NULL
)
384 if (mdb_vread(&uc
, sizeof (uc
), addr
) != sizeof (uc
)) {
385 mdb_warn("failed to read ucontext at %p", addr
);
389 return (wsp
->walk_callback(addr
, &uc
, wsp
->walk_cbdata
));
396 oldc_walk_fini(mdb_walk_state_t
*wsp
)
398 mdb_free(wsp
->walk_data
, wsp
->walk_addr
); /* walk_addr has size */
402 * ==================== threads ==========================
403 * These are the interfaces that used to require libthread.
404 * Now, libthread has been folded into libc.
405 * =======================================================
409 * prt_addr() is called up to three times to generate arguments for
410 * one call to mdb_printf(). We must return at least three different
411 * pointers to static storage for consecutive calls to prt_addr().
414 prt_addr(void *addr
, int pad
)
416 static char buffer
[4][24];
420 if (ix
== 4) /* use buffers in sequence: 0, 1, 2, 3 */
424 return (pad
? "<NULL> " : "<NULL>");
427 (void) mdb_snprintf(buf
, sizeof (buffer
[0]), "0x%016lx", addr
);
429 (void) strcpy(buf
+ 18, " ");
431 (void) mdb_snprintf(buf
, sizeof (buffer
[0]), "0x%08lx", addr
);
433 (void) strcpy(buf
+ 10, " ");
439 #define HD(str) mdb_printf(" " str "\n")
440 #define OFFSTR "+0x%-7lx "
441 #define OFFSET(member) ((size_t)OFFSETOF(ulwp_t, member))
445 d_ulwp(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
449 if (argc
!= 0 || !(flags
& DCMD_ADDRSPEC
))
452 if (mdb_vread(&ulwp
, sizeof (ulwp
), addr
) != sizeof (ulwp
) &&
453 (bzero(&ulwp
, sizeof (ulwp
)),
454 mdb_vread(&ulwp
, REPLACEMENT_SIZE
, addr
)) != REPLACEMENT_SIZE
) {
455 mdb_warn("failed to read ulwp at 0x%p", addr
);
459 mdb_printf("%#a\n", addr
);
462 mdb_printf(OFFSTR
"%s %s\n",
464 prt_addr(ulwp
.ul_self
, 1),
465 prt_addr(ulwp
.ul_uberdata
, 0));
467 HD("tlsent ntlsent");
468 mdb_printf(OFFSTR
"%s %ld\n",
470 prt_addr(ulwp
.ul_tlsent
, 1),
473 HD("forw back next");
474 mdb_printf(OFFSTR
"%s %s %s\n",
476 prt_addr(ulwp
.ul_forw
, 1),
477 prt_addr(ulwp
.ul_back
, 1),
478 prt_addr(ulwp
.ul_next
, 0));
481 mdb_printf(OFFSTR
"%s %s %s\n",
483 prt_addr(ulwp
.ul_hash
, 1),
484 prt_addr(ulwp
.ul_rval
, 1),
485 prt_addr(ulwp
.ul_stk
, 0));
487 HD("mapsiz guardsize stktop stksiz");
488 mdb_printf(OFFSTR
"%-10ld %-10ld %s %ld\n",
492 prt_addr((void *)ulwp
.ul_stktop
, 1),
495 HD("ustack.ss_sp ustack.ss_size ustack.ss_flags");
496 mdb_printf(OFFSTR
"%s %-21ld %s\n",
497 OFFSET(ul_ustack
.ss_sp
),
498 prt_addr(ulwp
.ul_ustack
.ss_sp
, 1),
499 ulwp
.ul_ustack
.ss_size
,
500 stack_flags(&ulwp
.ul_ustack
));
502 HD("ix lwpid pri epri policy cid");
503 mdb_printf(OFFSTR
"%-10d %-10d %-10d %-10d %-10d %d\n",
512 HD("cursig pleasestop stop signalled dead unwind");
513 mdb_printf(OFFSTR
"%-10d ",
516 mdb_printf(ulwp
.ul_pleasestop
? "0x%-8x " : "%-10d ",
518 mdb_printf(ulwp
.ul_stop
? "0x%-8x " : "%-10d ",
520 mdb_printf("%-10d %-10d %d\n",
525 HD("detached writer stopping can'prolog preempt savpreempt");
526 mdb_printf(OFFSTR
"%-10d %-10d %-10d %-10d %-10d %d\n",
531 ulwp
.ul_cancel_prologue
,
535 HD("sigsuspend main fork primarymap m'spinners d'noreserv");
536 mdb_printf(OFFSTR
"%-10d %-10d %-10d %-10d %-10d %d\n",
537 OFFSET(ul_sigsuspend
),
542 ulwp
.ul_max_spinners
,
543 ulwp
.ul_door_noreserve
);
545 HD("queue_fifo c'w'defer e'detect' async_safe rt rtqueued");
546 mdb_printf(OFFSTR
"%-10d %-10d %-10d %-10d %-10d %d\n",
547 OFFSET(ul_queue_fifo
),
549 ulwp
.ul_cond_wait_defer
,
550 ulwp
.ul_error_detection
,
555 HD("misaligned adapt'spin queue_spin critical sigdefer vfork");
556 mdb_printf(OFFSTR
"%-10d %-10d %-10d %-10d %-10d %d\n",
557 OFFSET(ul_misaligned
),
559 ulwp
.ul_adaptive_spin
,
565 HD("cancelable c'pending c'disabled c'async save_async mutator");
566 mdb_printf(OFFSTR
"%-10d %-10d %-10d %-10d %-10d %d\n",
567 OFFSET(ul_cancelable
),
569 ulwp
.ul_cancel_pending
,
570 ulwp
.ul_cancel_disabled
,
571 ulwp
.ul_cancel_async
,
575 HD("created replace nocancel errno errnop");
576 mdb_printf(OFFSTR
"%-10d %-10d %-10d %-10d %s\n",
582 prt_addr(ulwp
.ul_errnop
, 0));
584 HD("clnup_hdr schedctl_called schedctl");
585 mdb_printf(OFFSTR
"%s %s %s\n",
586 OFFSET(ul_clnup_hdr
),
587 prt_addr(ulwp
.ul_clnup_hdr
, 1),
588 prt_addr(ulwp
.ul_schedctl_called
, 1),
589 prt_addr((void *)ulwp
.ul_schedctl
, 0));
591 HD("bindflags libc_locks stsd &ftsd");
593 OFFSET(ul_bindflags
));
594 mdb_printf(ulwp
.ul_bindflags
? "0x%-8x " : "%-10d ",
596 mdb_printf("%-10d ", ulwp
.ul_libc_locks
);
597 mdb_printf("%s %s\n",
598 prt_addr(ulwp
.ul_stsd
, 1),
599 prt_addr((void *)(addr
+ OFFSET(ul_ftsd
[0])), 0));
601 HD("eventmask[0..1] eventnum eventdata");
602 mdb_printf(OFFSTR
"0x%08x 0x%08x %-21d %s\n",
603 OFFSET(ul_td_evbuf
.eventmask
.event_bits
[0]),
604 ulwp
.ul_td_evbuf
.eventmask
.event_bits
[0],
605 ulwp
.ul_td_evbuf
.eventmask
.event_bits
[1],
606 ulwp
.ul_td_evbuf
.eventnum
,
607 prt_addr(ulwp
.ul_td_evbuf
.eventdata
, 0));
609 HD("td'enable sync'reg qtype cv_wake rtld usropts");
610 mdb_printf(OFFSTR
"%-10d %-10d %-10d %-10d %-10d ",
611 OFFSET(ul_td_events_enable
),
612 ulwp
.ul_td_events_enable
,
613 ulwp
.ul_sync_obj_reg
,
617 mdb_printf(ulwp
.ul_usropts
? "0x%x\n" : "%d\n",
620 HD("startpc startarg wchan");
621 mdb_printf(OFFSTR
"%s %s %s\n",
623 prt_addr((void *)ulwp
.ul_startpc
, 1),
624 prt_addr(ulwp
.ul_startarg
, 1),
625 prt_addr(ulwp
.ul_wchan
, 0));
627 HD("link sleepq cvmutex");
628 mdb_printf(OFFSTR
"%s %s %s\n",
630 prt_addr(ulwp
.ul_link
, 1),
631 prt_addr(ulwp
.ul_sleepq
, 1),
632 prt_addr(ulwp
.ul_cvmutex
, 0));
634 HD("mxchain save_state");
635 mdb_printf(OFFSTR
"%s %d\n",
637 prt_addr(ulwp
.ul_mxchain
, 1),
640 HD("rdlockcnt rd_rwlock rd_count");
641 mdb_printf(OFFSTR
"%-21d %s %d\n",
642 OFFSET(ul_rdlockcnt
),
644 prt_addr(ulwp
.ul_readlock
.single
.rd_rwlock
, 1),
645 ulwp
.ul_readlock
.single
.rd_count
);
647 HD("heldlockcnt heldlocks tpdp");
648 mdb_printf(OFFSTR
"%-21d %s %s\n",
649 OFFSET(ul_heldlockcnt
),
651 prt_addr(ulwp
.ul_heldlocks
.single
, 1),
652 prt_addr(ulwp
.ul_tpdp
, 0));
654 HD("siglink s'l'spin s'l'spin2 s'l'sleep s'l'wakeup");
655 mdb_printf(OFFSTR
"%s %-10d %-10d %-10d %d\n",
657 prt_addr(ulwp
.ul_siglink
, 1),
658 ulwp
.ul_spin_lock_spin
,
659 ulwp
.ul_spin_lock_spin2
,
660 ulwp
.ul_spin_lock_sleep
,
661 ulwp
.ul_spin_lock_wakeup
);
663 HD("&queue_root rtclassid pilocks");
664 mdb_printf(OFFSTR
"%s %-10d %d\n",
665 OFFSET(ul_queue_root
),
666 prt_addr((void *)(addr
+ OFFSET(ul_queue_root
)), 1),
671 * The remainder of the ulwp_t structure
672 * is invalid if this is a replacement.
678 mdb_printf(OFFSTR
"0x%08x 0x%08x 0x%08x 0x%08x\n",
679 OFFSET(ul_sigmask
.__sigbits
[0]),
680 ulwp
.ul_sigmask
.__sigbits
[0],
681 ulwp
.ul_sigmask
.__sigbits
[1],
682 ulwp
.ul_sigmask
.__sigbits
[2],
683 ulwp
.ul_sigmask
.__sigbits
[3]);
686 mdb_printf(OFFSTR
"0x%08x 0x%08x 0x%08x 0x%08x\n",
687 OFFSET(ul_tmpmask
.__sigbits
[0]),
688 ulwp
.ul_tmpmask
.__sigbits
[0],
689 ulwp
.ul_tmpmask
.__sigbits
[1],
690 ulwp
.ul_tmpmask
.__sigbits
[2],
691 ulwp
.ul_tmpmask
.__sigbits
[3]);
693 HD("&siginfo &spinlock &fpuenv");
694 mdb_printf(OFFSTR
"%s %s %s\n",
696 prt_addr((void *)(addr
+ OFFSET(ul_siginfo
)), 1),
697 prt_addr((void *)(addr
+ OFFSET(ul_spinlock
)), 1),
698 prt_addr((void *)(addr
+ OFFSET(ul_fpuenv
)), 0));
700 HD("tmem.size &tmem.roots");
701 mdb_printf(OFFSTR
"%-21H %s\n",
703 ulwp
.ul_tmem
.tm_size
,
704 prt_addr((void *)(addr
+ OFFSET(ul_tmem
) + sizeof (size_t)), 0));
710 * Get the address of the unique uberdata_t structure.
719 if (mdb_lookup_by_obj("libc.so.1", "_tdb_bootstrap", &sym
) != 0) {
720 mdb_warn("cannot find libc.so.1`_tdb_bootstrap");
721 return ((uintptr_t)NULL
);
723 if (mdb_vread(&addr
, sizeof (addr
), sym
.st_value
) == sizeof (addr
) &&
724 addr
!= (uintptr_t)NULL
&&
725 mdb_vread(&uaddr
, sizeof (uaddr
), addr
) == sizeof (uaddr
) &&
726 uaddr
!= (uintptr_t)NULL
) {
729 if (mdb_lookup_by_obj("libc.so.1", "_uberdata", &sym
) != 0) {
730 mdb_warn("cannot find libc.so.1`_uberdata");
731 return ((uintptr_t)NULL
);
733 return ((uintptr_t)sym
.st_value
);
737 #define OFFSET(member) ((size_t)OFFSETOF(uberdata_t, member))
741 d_uberdata(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
748 if (!(flags
& DCMD_ADDRSPEC
) && (addr
= uberdata_addr()) == 0)
751 if (mdb_vread(&uberdata
, sizeof (uberdata
), addr
) !=
753 mdb_warn("failed to read uberdata at 0x%p", addr
);
757 mdb_printf("%#a\n", addr
);
759 HD("&link_lock &ld_lock &fork_lock");
760 mdb_printf(OFFSTR
"%s %s %s\n",
762 prt_addr((void *)(addr
+ OFFSET(link_lock
)), 1),
763 prt_addr((void *)(addr
+ OFFSET(ld_lock
)), 1),
764 prt_addr((void *)(addr
+ OFFSET(fork_lock
)), 0));
766 HD("&atfork_lock &callout_lock &tdb_hash_lock");
767 mdb_printf(OFFSTR
"%s %s %s\n",
769 prt_addr((void *)(addr
+ OFFSET(atfork_lock
)), 1),
770 prt_addr((void *)(addr
+ OFFSET(callout_lock
)), 1),
771 prt_addr((void *)(addr
+ OFFSET(tdb_hash_lock
)), 0));
773 HD("&tdb_hash_lock_stats &siguaction[0]");
774 mdb_printf(OFFSTR
"%s %s\n",
775 OFFSET(tdb_hash_lock_stats
),
776 prt_addr((void *)(addr
+ OFFSET(tdb_hash_lock_stats
)), 1),
777 prt_addr((void *)(addr
+ OFFSET(siguaction
)), 0));
779 HD("&bucket free_list chunks");
780 for (i
= 0; i
< NBUCKETS
; i
++) {
781 mdb_printf(OFFSTR
"%s %s %ld\n",
783 prt_addr((void *)(addr
+ OFFSET(bucket
[i
])), 1),
784 prt_addr(uberdata
.bucket
[i
].free_list
, 1),
785 uberdata
.bucket
[i
].chunks
);
788 HD("&atexit_root head exit_frame_monitor");
789 mdb_printf(OFFSTR
"%s %s %s\n",
791 prt_addr((void *)(addr
+ OFFSET(atexit_root
.exitfns_lock
)), 1),
792 prt_addr(uberdata
.atexit_root
.head
, 1),
793 prt_addr(uberdata
.atexit_root
.exit_frame_monitor
, 0));
795 HD("&quickexit_root head");
796 mdb_printf(OFFSTR
"%s %s\n",
797 OFFSET(quickexit_root
),
798 prt_addr((void *)(addr
+ OFFSET(quickexit_root
.exitfns_lock
)), 1),
799 prt_addr(uberdata
.quickexit_root
.head
, 0));
802 HD("&tsd_metadata tsdm_nkeys tsdm_nused tsdm_destro");
803 mdb_printf(OFFSTR
"%s %-10d %-10d %s\n",
804 OFFSET(tsd_metadata
),
805 prt_addr((void *)(addr
+ OFFSET(tsd_metadata
.tsdm_lock
)), 1),
806 uberdata
.tsd_metadata
.tsdm_nkeys
,
807 uberdata
.tsd_metadata
.tsdm_nused
,
808 prt_addr((void *)uberdata
.tsd_metadata
.tsdm_destro
, 0));
810 HD("&tls_metadata tls_modinfo.data tls_modinfo.size");
811 mdb_printf(OFFSTR
"%s %s %ld\n",
812 OFFSET(tls_metadata
),
813 prt_addr((void *)(addr
+ OFFSET(tls_metadata
.tls_lock
)), 1),
814 prt_addr(uberdata
.tls_metadata
.tls_modinfo
.tls_data
, 1),
815 uberdata
.tls_metadata
.tls_modinfo
.tls_size
);
817 HD(" static_tls.data static_tls.size");
818 mdb_printf(OFFSTR
"%s %s %ld\n",
819 OFFSET(tls_metadata
.static_tls
),
821 prt_addr(uberdata
.tls_metadata
.static_tls
.tls_data
, 1),
822 uberdata
.tls_metadata
.static_tls
.tls_size
);
824 HD("primary_ma bucket_ini uflags.mt uflags.pad uflags.trs uflags.ted");
825 mdb_printf(OFFSTR
"%-10d %-10d %-10d %-10d %-10d %d\n",
827 uberdata
.primary_map
,
828 uberdata
.bucket_init
,
829 uberdata
.uberflags
.uf_x
.x_mt
,
830 uberdata
.uberflags
.uf_x
.x_pad
,
831 uberdata
.uberflags
.uf_x
.x_tdb_register_sync
,
832 uberdata
.uberflags
.uf_x
.x_thread_error_detection
);
834 HD("queue_head thr_hash_table hash_size hash_mask");
835 mdb_printf(OFFSTR
"%s %s %-10d 0x%x\n",
837 prt_addr(uberdata
.queue_head
, 1),
838 prt_addr(uberdata
.thr_hash_table
, 1),
842 HD("ulwp_one all_lwps all_zombies");
843 mdb_printf(OFFSTR
"%s %s %s\n",
845 prt_addr(uberdata
.ulwp_one
, 1),
846 prt_addr(uberdata
.all_lwps
, 1),
847 prt_addr(uberdata
.all_zombies
, 0));
849 HD("nthreads nzombies ndaemons pid sigacthandler");
850 mdb_printf(OFFSTR
"%-10d %-10d %-10d %-10d %s\n",
856 prt_addr((void *)uberdata
.sigacthandler
, 0));
858 HD("lwp_stacks lwp_laststack nfreestack stk_cache");
859 mdb_printf(OFFSTR
"%s %s %-10d %d\n",
861 prt_addr(uberdata
.lwp_stacks
, 1),
862 prt_addr(uberdata
.lwp_laststack
, 1),
864 uberdata
.thread_stack_cache
);
866 HD("ulwp_freelist ulwp_lastfree ulwp_replace_free");
867 mdb_printf(OFFSTR
"%s %s %s\n",
868 OFFSET(ulwp_freelist
),
869 prt_addr(uberdata
.ulwp_freelist
, 1),
870 prt_addr(uberdata
.ulwp_lastfree
, 1),
871 prt_addr(uberdata
.ulwp_replace_free
, 0));
873 HD("ulwp_replace_last atforklist");
874 mdb_printf(OFFSTR
"%s %s\n",
875 OFFSET(ulwp_replace_last
),
876 prt_addr(uberdata
.ulwp_replace_last
, 1),
877 prt_addr(uberdata
.atforklist
, 0));
879 HD("robustlocks robustlist progname");
880 mdb_printf(OFFSTR
"%s %s %s\n",
882 prt_addr(uberdata
.robustlocks
, 1),
883 prt_addr(uberdata
.robustlist
, 1),
884 prt_addr(uberdata
.progname
, 0));
886 HD("tdb_bootstrap tdb_sync_addr_hash tdb_'count tdb_'fail");
887 mdb_printf(OFFSTR
"%s %s %-10d %d\n",
888 OFFSET(tdb_bootstrap
),
889 prt_addr(uberdata
.tdb_bootstrap
, 1),
890 prt_addr(uberdata
.tdb
.tdb_sync_addr_hash
, 1),
891 uberdata
.tdb
.tdb_register_count
,
892 uberdata
.tdb
.tdb_hash_alloc_failed
);
894 HD("tdb_sync_addr_free tdb_sync_addr_last tdb_sync_alloc");
895 mdb_printf(OFFSTR
"%s %s %ld\n",
896 OFFSET(tdb
.tdb_sync_addr_free
),
897 prt_addr(uberdata
.tdb
.tdb_sync_addr_free
, 1),
898 prt_addr(uberdata
.tdb
.tdb_sync_addr_last
, 1),
899 uberdata
.tdb
.tdb_sync_alloc
);
901 HD("tdb_ev_global_mask tdb_events");
902 mdb_printf(OFFSTR
"0x%08x 0x%08x %s\n",
903 OFFSET(tdb
.tdb_ev_global_mask
),
904 uberdata
.tdb
.tdb_ev_global_mask
.event_bits
[0],
905 uberdata
.tdb
.tdb_ev_global_mask
.event_bits
[1],
906 prt_addr((void *)uberdata
.tdb
.tdb_events
, 0));
912 ulwp_walk_init(mdb_walk_state_t
*wsp
)
914 uintptr_t addr
= wsp
->walk_addr
;
918 offset
= mdb_ctf_offsetof_by_name("uberdata_t", "all_lwps");
920 offset
= OFFSETOF(uberdata_t
, all_lwps
);
921 mdb_warn("CTF data is missing for uberdata_t; using current "
922 "platform's offset for uberdata.all_lwps");
925 if (addr
== (uintptr_t)NULL
&&
926 ((uber_addr
= uberdata_addr()) == (uintptr_t)NULL
||
927 mdb_vread(&addr
, sizeof (addr
), uber_addr
+ offset
)
929 mdb_warn("cannot find 'uberdata.all_lwps'");
932 if (addr
== (uintptr_t)NULL
)
934 wsp
->walk_addr
= addr
;
935 wsp
->walk_data
= (void *)addr
;
940 ulwp_walk_step(mdb_walk_state_t
*wsp
)
942 uintptr_t addr
= wsp
->walk_addr
;
945 if (addr
== (uintptr_t)NULL
)
947 if (mdb_vread(&ulwp
, sizeof (ulwp
), addr
) != sizeof (ulwp
) &&
948 (bzero(&ulwp
, sizeof (ulwp
)),
949 mdb_vread(&ulwp
, REPLACEMENT_SIZE
, addr
)) != REPLACEMENT_SIZE
) {
950 mdb_warn("failed to read ulwp at 0x%p", addr
);
954 * If we have looped around to the beginning
955 * of the circular linked list, we are done.
957 if ((wsp
->walk_addr
= (uintptr_t)ulwp
.ul_forw
)
958 == (uintptr_t)wsp
->walk_data
)
959 wsp
->walk_addr
= (uintptr_t)NULL
;
960 return (wsp
->walk_callback(addr
, &ulwp
, wsp
->walk_cbdata
));
963 /* Avoid classifying NULL pointers as part of the main stack on x86 */
964 #define MIN_STACK_ADDR (0x10000ul)
967 whatis_walk_ulwp(uintptr_t addr
, const ulwp_t
*ulwp
, mdb_whatis_t
*w
)
970 lwpid_t id
= ulwp
->ul_lwpid
;
971 uintptr_t top
, base
, size
;
973 while (mdb_whatis_match(w
, addr
, sizeof (ulwp_t
), &cur
))
974 mdb_whatis_report_object(w
, cur
, addr
,
975 "allocated as thread %#r's ulwp_t\n", id
);
977 top
= (uintptr_t)ulwp
->ul_stktop
;
978 size
= ulwp
->ul_stksiz
;
981 * The main stack ends up being a little weird, especially if
982 * the stack ulimit is unlimited. This tries to take that into
987 if (top
> MIN_STACK_ADDR
&& top
- size
< MIN_STACK_ADDR
)
988 size
= top
- MIN_STACK_ADDR
;
992 while (mdb_whatis_match(w
, base
, size
, &cur
))
993 mdb_whatis_report_address(w
, cur
, "in [ stack tid=%#r ]\n", id
);
995 if (ulwp
->ul_ustack
.ss_flags
& SS_ONSTACK
) {
996 base
= (uintptr_t)ulwp
->ul_ustack
.ss_sp
;
997 size
= ulwp
->ul_ustack
.ss_size
;
999 while (mdb_whatis_match(w
, base
, size
, &cur
))
1000 mdb_whatis_report_address(w
, cur
,
1001 "in [ altstack tid=%#r ]\n", id
);
1004 return (WHATIS_WALKRET(w
));
1009 whatis_run_ulwps(mdb_whatis_t
*w
, void *arg
)
1011 if (mdb_walk("ulwps", (mdb_walk_cb_t
)whatis_walk_ulwp
, w
) == -1) {
1012 mdb_warn("couldn't find ulwps walker");
1019 * =======================================================
1020 * End of thread (previously libthread) interfaces.
1021 * ==================== threads ==========================
1025 stacks_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
1027 int rval
= stacks(addr
, flags
, argc
, argv
);
1030 * For the user-level variant of ::stacks, we don't bother caching
1031 * state, as even a very large program is unlikely to compare to the
1032 * kernel in terms of number of threads. (And if you find yourself
1033 * here in anger, frustrated about how long ::stacks is running on
1034 * your galactically complicated zillion-thread program, hopefully
1035 * you will find some solace in the irony. Okay, probably not...)
1037 stacks_cleanup(B_TRUE
);
1041 typedef struct tid2ulwp_walk
{
1044 boolean_t t2u_found
;
1049 tid2ulwp_walk(uintptr_t addr
, ulwp_t
*ulwp
, tid2ulwp_walk_t
*t2u
)
1051 if (ulwp
->ul_lwpid
== t2u
->t2u_tid
) {
1052 t2u
->t2u_lwp
= addr
;
1053 t2u
->t2u_found
= B_TRUE
;
1061 tid2ulwp_impl(uintptr_t tid_addr
, uintptr_t *ulwp_addrp
)
1063 tid2ulwp_walk_t t2u
;
1065 bzero(&t2u
, sizeof (t2u
));
1066 t2u
.t2u_tid
= (lwpid_t
)tid_addr
;
1068 if (mdb_walk("ulwp", (mdb_walk_cb_t
)tid2ulwp_walk
, &t2u
) != 0) {
1069 mdb_warn("can't walk 'ulwp'");
1073 if (!t2u
.t2u_found
) {
1074 mdb_warn("thread ID %d not found", t2u
.t2u_tid
);
1077 *ulwp_addrp
= t2u
.t2u_lwp
;
1083 tid2ulwp(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
1085 uintptr_t ulwp_addr
;
1089 return (DCMD_USAGE
);
1091 error
= tid2ulwp_impl(addr
, &ulwp_addr
);
1092 if (error
== DCMD_OK
)
1093 mdb_printf("%p\n", ulwp_addr
);
1097 typedef struct mdb_libc_ulwp
{
1098 void *ul_ftsd
[TSD_NFAST
];
1103 * Map from thread pointer to tsd for given key
1106 d_tsd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
1109 uintptr_t ulwp_addr
;
1110 uintptr_t key
= (uintptr_t)NULL
;
1111 void *element
= NULL
;
1113 if (mdb_getopts(argc
, argv
, 'k', MDB_OPT_UINTPTR
, &key
, NULL
) != argc
)
1114 return (DCMD_USAGE
);
1116 if (!(flags
& DCMD_ADDRSPEC
) || key
== (uintptr_t)NULL
)
1117 return (DCMD_USAGE
);
1119 if (tid2ulwp_impl(addr
, &ulwp_addr
) != DCMD_OK
)
1122 if (mdb_ctf_vread(&u
, "ulwp_t", "mdb_libc_ulwp_t", ulwp_addr
, 0) == -1)
1125 if (key
< TSD_NFAST
) {
1126 element
= u
.ul_ftsd
[key
];
1127 } else if (u
.ul_stsd
!= NULL
) {
1129 /* tsd_t is a union, so we can't use ctf_vread() on it. */
1130 if (mdb_vread(&nalloc
, sizeof (nalloc
),
1131 (uintptr_t)&u
.ul_stsd
->tsd_nalloc
) == -1) {
1132 mdb_warn("failed to read tsd_t at %p", u
.ul_stsd
);
1136 if (mdb_vread(&element
, sizeof (element
),
1137 (uintptr_t)&u
.ul_stsd
->tsd_data
[key
]) == -1) {
1138 mdb_warn("failed to read tsd_t at %p",
1145 if (element
== NULL
&& (flags
& DCMD_PIPE
))
1148 mdb_printf("%p\n", element
);
1152 static const mdb_dcmd_t dcmds
[] = {
1153 { "jmp_buf", ":", "print jmp_buf contents", d_jmp_buf
, NULL
},
1154 { "sigjmp_buf", ":", "print sigjmp_buf contents", d_sigjmp_buf
, NULL
},
1155 { "siginfo", ":", "print siginfo_t structure", d_siginfo
, NULL
},
1156 { "stacks", "?[-afiv] [-c func] [-C func] [-m module] [-M module] ",
1157 "print unique thread stacks", stacks_dcmd
, stacks_help
},
1158 { "tid2ulwp", "?", "convert TID to ulwp_t address", tid2ulwp
},
1159 { "ucontext", ":", "print ucontext_t structure", d_ucontext
, NULL
},
1160 { "ulwp", ":", "print ulwp_t structure", d_ulwp
, NULL
},
1161 { "uberdata", ":", "print uberdata_t structure", d_uberdata
, NULL
},
1162 { "tsd", ":-k key", "print tsd for this thread", d_tsd
, NULL
},
1166 static const mdb_walker_t walkers
[] = {
1167 { "ucontext", "walk ucontext_t uc_link list",
1168 NULL
, uc_walk_step
, NULL
, NULL
},
1169 { "oldcontext", "walk per-lwp oldcontext pointers",
1170 oldc_walk_init
, oldc_walk_step
, oldc_walk_fini
, NULL
},
1171 { "ulwps", "walk list of ulwp_t pointers",
1172 ulwp_walk_init
, ulwp_walk_step
, NULL
, NULL
},
1173 { "ulwp", "walk list of ulwp_t pointers",
1174 ulwp_walk_init
, ulwp_walk_step
, NULL
, NULL
},
1178 static const mdb_modinfo_t modinfo
= { MDB_API_VERSION
, dcmds
, walkers
};
1180 const mdb_modinfo_t
*
1183 mdb_whatis_register("threads", whatis_run_ulwps
, NULL
,
1184 WHATIS_PRIO_EARLY
, WHATIS_REG_NO_ID
);