17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
53470957raf * Common Development and Distribution License (the "License").
63470957raf * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
213470957raf
227c478bdstevel@tonic-gate/*
233cd8a1aRoger A. Faulkner * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
2428e4da2Matthew Ahrens * Copyright (c) 2012 by Delphix. All rights reserved.
25542a7b7Carlos Neira * Copyright (c) 2019 Carlos Neira <cneirabustos@gmail.com>
26542a7b7Carlos Neira * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
270718894Jason King * Copyright 2019 Joyent, Inc.
284f364e7Robert Mustacchi */
297c478bdstevel@tonic-gate
307c478bdstevel@tonic-gate#include <sys/mdb_modapi.h>
314a1c243Jonathan Adams#include <mdb/mdb_whatis.h>
3228e4da2Matthew Ahrens#include <mdb/mdb_ctf.h>
337c478bdstevel@tonic-gate#include <procfs.h>
347c478bdstevel@tonic-gate#include <ucontext.h>
357c478bdstevel@tonic-gate#include <siginfo.h>
367c478bdstevel@tonic-gate#include <signal.h>
377c478bdstevel@tonic-gate#include <setjmp.h>
387c478bdstevel@tonic-gate#include <string.h>
397c478bdstevel@tonic-gate#include <thr_uberdata.h>
40c9a6ea2Bryan Cantrill#include "findstack.h"
41542a7b7Carlos Neira#include <libproc.h>
427c478bdstevel@tonic-gate
437c478bdstevel@tonic-gatestatic const char *
447c478bdstevel@tonic-gatestack_flags(const stack_t *sp)
457c478bdstevel@tonic-gate{
467c478bdstevel@tonic-gate	static char buf[32];
477c478bdstevel@tonic-gate
487c478bdstevel@tonic-gate	if (sp->ss_flags == 0)
497c478bdstevel@tonic-gate		(void) strcpy(buf, " 0");
507c478bdstevel@tonic-gate	else if (sp->ss_flags & ~(SS_ONSTACK | SS_DISABLE))
517c478bdstevel@tonic-gate		(void) mdb_snprintf(buf, sizeof (buf), " 0x%x", sp->ss_flags);
527c478bdstevel@tonic-gate	else {
537c478bdstevel@tonic-gate		buf[0] = '\0';
547c478bdstevel@tonic-gate		if (sp->ss_flags & SS_ONSTACK)
557c478bdstevel@tonic-gate			(void) strcat(buf, "|ONSTACK");
567c478bdstevel@tonic-gate		if (sp->ss_flags & SS_DISABLE)
577c478bdstevel@tonic-gate			(void) strcat(buf, "|DISABLE");
587c478bdstevel@tonic-gate	}
597c478bdstevel@tonic-gate
607c478bdstevel@tonic-gate	return (buf + 1);
617c478bdstevel@tonic-gate}
627c478bdstevel@tonic-gate
637c478bdstevel@tonic-gate/*ARGSUSED*/
647c478bdstevel@tonic-gatestatic int
657c478bdstevel@tonic-gated_jmp_buf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
667c478bdstevel@tonic-gate{
677c478bdstevel@tonic-gate	jmp_buf jb;
687c478bdstevel@tonic-gate	const ulong_t *b = (const ulong_t *)jb;
697c478bdstevel@tonic-gate
707c478bdstevel@tonic-gate	if (argc != 0)
717c478bdstevel@tonic-gate		return (DCMD_USAGE);
727c478bdstevel@tonic-gate
737c478bdstevel@tonic-gate	if (mdb_vread(&jb, sizeof (jb), addr) != sizeof (jb)) {
747c478bdstevel@tonic-gate		mdb_warn("failed to read jmp_buf at %p", addr);
757c478bdstevel@tonic-gate		return (DCMD_ERR);
767c478bdstevel@tonic-gate	}
777c478bdstevel@tonic-gate
787c478bdstevel@tonic-gate#if defined(__sparc)
797c478bdstevel@tonic-gate	mdb_printf("  %%sp = 0x%lx\n", b[1]);
807c478bdstevel@tonic-gate	mdb_printf("  %%pc = 0x%lx %lA\n", b[2], b[2]);
817c478bdstevel@tonic-gate	mdb_printf("  %%fp = 0x%lx\n", b[3]);
827c478bdstevel@tonic-gate	mdb_printf("  %%i7 = 0x%lx %lA\n", b[4], b[4]);
837c478bdstevel@tonic-gate#elif defined(__amd64)
847c478bdstevel@tonic-gate	mdb_printf("  %%rbx = 0x%lx\n", b[0]);
857c478bdstevel@tonic-gate	mdb_printf("  %%r12 = 0x%lx\n", b[1]);
867c478bdstevel@tonic-gate	mdb_printf("  %%r13 = 0x%lx\n", b[2]);
877c478bdstevel@tonic-gate	mdb_printf("  %%r14 = 0x%lx\n", b[3]);
887c478bdstevel@tonic-gate	mdb_printf("  %%r15 = 0x%lx\n", b[4]);
897c478bdstevel@tonic-gate	mdb_printf("  %%rbp = 0x%lx\n", b[5]);
907c478bdstevel@tonic-gate	mdb_printf("  %%rsp = 0x%lx\n", b[6]);
917c478bdstevel@tonic-gate	mdb_printf("  %%rip = 0x%lx %lA\n", b[7], b[7]);
927c478bdstevel@tonic-gate#elif defined(__i386)
937c478bdstevel@tonic-gate	mdb_printf("  %%ebx = 0x%lx\n", b[0]);
947c478bdstevel@tonic-gate	mdb_printf("  %%esi = 0x%lx\n", b[1]);
957c478bdstevel@tonic-gate	mdb_printf("  %%edi = 0x%lx\n", b[2]);
967c478bdstevel@tonic-gate	mdb_printf("  %%ebp = 0x%lx\n", b[3]);
977c478bdstevel@tonic-gate	mdb_printf("  %%esp = 0x%lx\n", b[4]);
987c478bdstevel@tonic-gate	mdb_printf("  %%eip = 0x%lx %lA\n", b[5], b[5]);
997c478bdstevel@tonic-gate#endif
1007c478bdstevel@tonic-gate	return (DCMD_OK);
1017c478bdstevel@tonic-gate}
1027c478bdstevel@tonic-gate
1038f88a51Joshua M. Clulowconst mdb_bitmask_t uc_flags_bits[] = {
1048f88a51Joshua M. Clulow	{ "UC_SIGMASK", UC_SIGMASK, UC_SIGMASK },
1058f88a51Joshua M. Clulow	{ "UC_STACK", UC_STACK, UC_STACK },
1068f88a51Joshua M. Clulow	{ "UC_CPU", UC_CPU, UC_CPU },
1078f88a51Joshua M. Clulow	{ "UC_FPU", UC_FPU, UC_FPU },
1088f88a51Joshua M. Clulow#if defined(UC_INTR)
1098f88a51Joshua M. Clulow	{ "UC_INTR", UC_INTR, UC_INTR },
1108f88a51Joshua M. Clulow#endif
1118f88a51Joshua M. Clulow#if defined(UC_ASR)
1128f88a51Joshua M. Clulow	{ "UC_ASR", UC_ASR, UC_ASR },
1138f88a51Joshua M. Clulow#endif
1148f88a51Joshua M. Clulow	{ NULL, 0, 0 }
1158f88a51Joshua M. Clulow};
1168f88a51Joshua M. Clulow
1177c478bdstevel@tonic-gate/*ARGSUSED*/
1187c478bdstevel@tonic-gatestatic int
1197c478bdstevel@tonic-gated_ucontext(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1207c478bdstevel@tonic-gate{
1217c478bdstevel@tonic-gate	ucontext_t uc;
1227c478bdstevel@tonic-gate
1237c478bdstevel@tonic-gate	if (argc != 0)
1247c478bdstevel@tonic-gate		return (DCMD_USAGE);
1257c478bdstevel@tonic-gate
1267c478bdstevel@tonic-gate	if (mdb_vread(&uc, sizeof (uc), addr) != sizeof (uc)) {
1277c478bdstevel@tonic-gate		mdb_warn("failed to read ucontext at %p", addr);
1287c478bdstevel@tonic-gate		return (DCMD_ERR);
1297c478bdstevel@tonic-gate	}
1307c478bdstevel@tonic-gate
1318f88a51Joshua M. Clulow	mdb_printf("  flags    = 0x%lx <%b>\n", uc.uc_flags,
1328f88a51Joshua M. Clulow	    (uint_t)uc.uc_flags, uc_flags_bits);
1337c478bdstevel@tonic-gate	mdb_printf("  link     = 0x%p\n", uc.uc_link);
1347c478bdstevel@tonic-gate	mdb_printf("  sigmask  = 0x%08x 0x%08x 0x%08x 0x%08x\n",
1357c478bdstevel@tonic-gate	    uc.uc_sigmask.__sigbits[0], uc.uc_sigmask.__sigbits[1],
1367c478bdstevel@tonic-gate	    uc.uc_sigmask.__sigbits[2], uc.uc_sigmask.__sigbits[3]);
1377c478bdstevel@tonic-gate	mdb_printf("  stack    = sp 0x%p size 0x%lx flags %s\n",
1387c478bdstevel@tonic-gate	    uc.uc_stack.ss_sp, uc.uc_stack.ss_size, stack_flags(&uc.uc_stack));
1397c478bdstevel@tonic-gate	mdb_printf("  mcontext = 0x%p\n",
1407c478bdstevel@tonic-gate	    addr + OFFSETOF(ucontext_t, uc_mcontext));
1417c478bdstevel@tonic-gate
1427c478bdstevel@tonic-gate	return (DCMD_OK);
1437c478bdstevel@tonic-gate}
1447c478bdstevel@tonic-gate
1457c478bdstevel@tonic-gate/*ARGSUSED*/
1467c478bdstevel@tonic-gatestatic int
1477c478bdstevel@tonic-gated_sigjmp_buf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1487c478bdstevel@tonic-gate{
1497c478bdstevel@tonic-gate#if defined(__sparc)
1507c478bdstevel@tonic-gate	struct {
1517c478bdstevel@tonic-gate		int sjs_flags;
1527c478bdstevel@tonic-gate		greg_t sjs_sp;
1537c478bdstevel@tonic-gate		greg_t sjs_pc;
1547c478bdstevel@tonic-gate		greg_t sjs_fp;
1557c478bdstevel@tonic-gate		greg_t sjs_i7;
1567c478bdstevel@tonic-gate		ucontext_t *sjs_uclink;
1577c478bdstevel@tonic-gate		ulong_t sjs_pad[_JBLEN - 6];
1587c478bdstevel@tonic-gate		sigset_t sjs_sigmask;
1597c478bdstevel@tonic-gate#if defined(_LP64)
1603cd8a1aRoger A. Faulkner		greg_t sjs_asi;
1613cd8a1aRoger A. Faulkner		greg_t sjs_fprs;
1627c478bdstevel@tonic-gate#endif
1637c478bdstevel@tonic-gate		stack_t sjs_stack;
1647c478bdstevel@tonic-gate	} s;
1657c478bdstevel@tonic-gate
1667c478bdstevel@tonic-gate	if (argc != 0)
1677c478bdstevel@tonic-gate		return (DCMD_USAGE);
1687c478bdstevel@tonic-gate
1697c478bdstevel@tonic-gate	if (mdb_vread(&s, sizeof (s), addr) != sizeof (s)) {
1707c478bdstevel@tonic-gate		mdb_warn("failed to read sigjmp_buf at %p", addr);
1717c478bdstevel@tonic-gate		return (DCMD_ERR);
1727c478bdstevel@tonic-gate	}
1737c478bdstevel@tonic-gate
1747c478bdstevel@tonic-gate	mdb_printf("  flags  = 0x%x\n", s.sjs_flags);
1757c478bdstevel@tonic-gate	mdb_printf("  %%sp    = 0x%lx %lA\n", s.sjs_sp, s.sjs_sp);
1767c478bdstevel@tonic-gate	mdb_printf("  %%pc    = 0x%lx %lA\n", s.sjs_pc, s.sjs_pc);
1777c478bdstevel@tonic-gate	mdb_printf("  %%fp    = 0x%lx %lA\n", s.sjs_fp, s.sjs_fp);
1787c478bdstevel@tonic-gate	mdb_printf("  %%i7    = 0x%lx %lA\n", s.sjs_i7, s.sjs_i7);
1797c478bdstevel@tonic-gate	mdb_printf("  uclink = %p\n", s.sjs_uclink);
1807c478bdstevel@tonic-gate	mdb_printf("  sigset = 0x%08x 0x%08x 0x%08x 0x%08x\n",
1817c478bdstevel@tonic-gate	    s.sjs_sigmask.__sigbits[0], s.sjs_sigmask.__sigbits[1],
1827c478bdstevel@tonic-gate	    s.sjs_sigmask.__sigbits[2], s.sjs_sigmask.__sigbits[3]);
1833cd8a1aRoger A. Faulkner#if defined(_LP64)
1843cd8a1aRoger A. Faulkner	mdb_printf("  %%asi   = 0x%lx\n", s.sjs_asi);
1853cd8a1aRoger A. Faulkner	mdb_printf("  %%fprs  = 0x%lx\n", s.sjs_fprs);
1863cd8a1aRoger A. Faulkner#endif
1877c478bdstevel@tonic-gate	mdb_printf("  stack  = sp 0x%p size 0x%lx flags %s\n",
1887c478bdstevel@tonic-gate	    s.sjs_stack.ss_sp, s.sjs_stack.ss_size, stack_flags(&s.sjs_stack));
1897c478bdstevel@tonic-gate
1907c478bdstevel@tonic-gate	return (DCMD_OK);
1917c478bdstevel@tonic-gate
1927c478bdstevel@tonic-gate#elif defined(__i386) || defined(__amd64)
1937c478bdstevel@tonic-gate	return (d_ucontext(addr, flags, argc, argv));
1947c478bdstevel@tonic-gate#endif
1957c478bdstevel@tonic-gate}
1967c478bdstevel@tonic-gate
1977c478bdstevel@tonic-gate/*ARGSUSED*/
1987c478bdstevel@tonic-gatestatic int
1997c478bdstevel@tonic-gated_siginfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2007c478bdstevel@tonic-gate{
2017c478bdstevel@tonic-gate	static const char *const msname[] = {
2027c478bdstevel@tonic-gate		"USER", "SYSTEM", "TRAP", "TFAULT", "DFAULT", "KFAULT",
2037c478bdstevel@tonic-gate		"USER_LOCK", "SLEEP", "WAIT_CPU", "STOPPED"
2047c478bdstevel@tonic-gate	};
2057c478bdstevel@tonic-gate
2067c478bdstevel@tonic-gate	char signame[SIG2STR_MAX];
2077c478bdstevel@tonic-gate	siginfo_t si;
2087c478bdstevel@tonic-gate	int i;
2097c478bdstevel@tonic-gate
2107c478bdstevel@tonic-gate	if (argc != 0)
2117c478bdstevel@tonic-gate		return (DCMD_USAGE);
2127c478bdstevel@tonic-gate
2137c478bdstevel@tonic-gate	if (mdb_vread(&si, sizeof (si), addr) != sizeof (si)) {
2147c478bdstevel@tonic-gate		mdb_warn("failed to read siginfo at %p", addr);
2157c478bdstevel@tonic-gate		return (DCMD_ERR);
2167c478bdstevel@tonic-gate	}
2177c478bdstevel@tonic-gate
2187c478bdstevel@tonic-gate	if (sig2str(si.si_signo, signame) == -1)
2197c478bdstevel@tonic-gate		(void) strcpy(signame, "unknown");
2207c478bdstevel@tonic-gate
2217c478bdstevel@tonic-gate	mdb_printf("  signal %5d (%s)\n", si.si_signo, signame);
2227c478bdstevel@tonic-gate	mdb_printf("  code   %5d (", si.si_code);
2237c478bdstevel@tonic-gate
2247c478bdstevel@tonic-gate	switch (si.si_code) {
2257c478bdstevel@tonic-gate	case SI_NOINFO:
2267c478bdstevel@tonic-gate		mdb_printf("no info");
2277c478bdstevel@tonic-gate		break;
2287c478bdstevel@tonic-gate	case SI_DTRACE:
2297c478bdstevel@tonic-gate		mdb_printf("from DTrace raise() action");
2307c478bdstevel@tonic-gate		break;
2317c478bdstevel@tonic-gate	case SI_RCTL:
2327c478bdstevel@tonic-gate		mdb_printf("from rctl action");
2337c478bdstevel@tonic-gate		break;
2347c478bdstevel@tonic-gate	case SI_USER:
2357c478bdstevel@tonic-gate		mdb_printf("user generated via kill");
2367c478bdstevel@tonic-gate		break;
2377c478bdstevel@tonic-gate	case SI_LWP:
2387c478bdstevel@tonic-gate		mdb_printf("user generated via lwp_kill");
2397c478bdstevel@tonic-gate		break;
2407c478bdstevel@tonic-gate	case SI_QUEUE:
2417c478bdstevel@tonic-gate		mdb_printf("user generated via sigqueue");
2427c478bdstevel@tonic-gate		break;
2437c478bdstevel@tonic-gate	case SI_TIMER:
2447c478bdstevel@tonic-gate		mdb_printf("from timer expiration");
2457c478bdstevel@tonic-gate		break;
2467c478bdstevel@tonic-gate	case SI_ASYNCIO:
2477c478bdstevel@tonic-gate		mdb_printf("from async i/o completion");
2487c478bdstevel@tonic-gate		break;
2497c478bdstevel@tonic-gate	case SI_MESGQ:
2507c478bdstevel@tonic-gate		mdb_printf("from message arrival");
2517c478bdstevel@tonic-gate		break;
2527c478bdstevel@tonic-gate	default:
2537c478bdstevel@tonic-gate		if (SI_FROMUSER(&si))
2547c478bdstevel@tonic-gate			mdb_printf("from user process");
2557c478bdstevel@tonic-gate		else
2567c478bdstevel@tonic-gate			mdb_printf("from kernel");
2577c478bdstevel@tonic-gate	}
2587c478bdstevel@tonic-gate
2597c478bdstevel@tonic-gate	mdb_printf(")\n  errno  %5d (%s)\n",
2607c478bdstevel@tonic-gate	    si.si_errno, strerror(si.si_errno));
2617c478bdstevel@tonic-gate
2627c478bdstevel@tonic-gate	if (si.si_code == SI_USER || si.si_code == SI_QUEUE) {
2637c478bdstevel@tonic-gate		mdb_printf("  signal sent from PID %d (uid %d)\n",
2647c478bdstevel@tonic-gate		    si.si_pid, si.si_uid);
2657c478bdstevel@tonic-gate	}
2667c478bdstevel@tonic-gate
2677c478bdstevel@tonic-gate	if (si.si_code == SI_QUEUE) {
2687c478bdstevel@tonic-gate		mdb_printf("  signal value = 0t%d / %p\n",
2697c478bdstevel@tonic-gate		    si.si_value.sival_int, si.si_value.sival_ptr);
2707c478bdstevel@tonic-gate	}
2717c478bdstevel@tonic-gate
2727c478bdstevel@tonic-gate	switch (si.si_signo) {
2737c478bdstevel@tonic-gate	case SIGCLD:
2747c478bdstevel@tonic-gate		mdb_printf("  signal sent from child PID %d (uid %d)\n",
2757c478bdstevel@tonic-gate		    si.si_pid, si.si_uid);
2767c478bdstevel@tonic-gate		mdb_printf("  usr time = 0t%ld ticks, sys time = 0t%ld ticks\n",
2777c478bdstevel@tonic-gate		    si.si_utime, si.si_stime);
2787c478bdstevel@tonic-gate		mdb_printf("  wait status = 0x%x\n", si.si_status);
2797c478bdstevel@tonic-gate		break;
2807c478bdstevel@tonic-gate
2817c478bdstevel@tonic-gate	case SIGSEGV:
2827c478bdstevel@tonic-gate	case SIGBUS:
2837c478bdstevel@tonic-gate	case SIGILL:
2847c478bdstevel@tonic-gate	case SIGTRAP:
2857c478bdstevel@tonic-gate	case SIGFPE:
2867c478bdstevel@tonic-gate		mdb_printf("  fault address = 0x%p\n  trapno = %d\n",
2877c478bdstevel@tonic-gate		    si.si_addr, si.si_trapno);
2887c478bdstevel@tonic-gate		mdb_printf("  instruction address = 0x%p %lA\n",
2897c478bdstevel@tonic-gate		    si.si_pc, si.si_pc);
2907c478bdstevel@tonic-gate		break;
2917c478bdstevel@tonic-gate
2927c478bdstevel@tonic-gate	case SIGPOLL:
2937c478bdstevel@tonic-gate	case SIGXFSZ:
2947c478bdstevel@tonic-gate		mdb_printf("  fd = %d  band = 0x%lx\n",
2957c478bdstevel@tonic-gate		    si.si_fd, si.si_band);
2967c478bdstevel@tonic-gate		break;
2977c478bdstevel@tonic-gate
2987c478bdstevel@tonic-gate	case SIGPROF:
2997c478bdstevel@tonic-gate		mdb_printf("  last fault address = 0x%p fault type = %d\n",
3007c478bdstevel@tonic-gate		    si.si_faddr, si.si_fault);
3017c478bdstevel@tonic-gate		mdb_printf("  timestamp = 0t%ld sec 0t%ld nsec\n",
3027c478bdstevel@tonic-gate		    si.si_tstamp.tv_sec, si.si_tstamp.tv_nsec);
3037c478bdstevel@tonic-gate
3047c478bdstevel@tonic-gate		if (si.__data.__prof.__syscall != 0) {
3057c478bdstevel@tonic-gate			mdb_printf("  system call %d (", si.si_syscall);
3067c478bdstevel@tonic-gate			if (si.si_nsysarg > 0) {
3077c478bdstevel@tonic-gate				mdb_printf("%lx", si.si_sysarg[0]);
3087c478bdstevel@tonic-gate				for (i = 1; i < si.si_nsysarg; i++)
3097c478bdstevel@tonic-gate					mdb_printf(", %lx", si.si_sysarg[i]);
3107c478bdstevel@tonic-gate			}
3117c478bdstevel@tonic-gate			mdb_printf("  )\n");
3127c478bdstevel@tonic-gate		}
3137c478bdstevel@tonic-gate
3147c478bdstevel@tonic-gate		for (i = 0; i < sizeof (msname) / sizeof (msname[0]); i++) {
3157c478bdstevel@tonic-gate			mdb_printf("  mstate[\"%s\"] = %d\n",
3167c478bdstevel@tonic-gate			    msname[i], si.si_mstate[i]);
3177c478bdstevel@tonic-gate		}
3187c478bdstevel@tonic-gate		break;
3197c478bdstevel@tonic-gate	}
3207c478bdstevel@tonic-gate
3217c478bdstevel@tonic-gate	return (DCMD_OK);
3227c478bdstevel@tonic-gate}
3237c478bdstevel@tonic-gate
3247c478bdstevel@tonic-gatestatic int
3257c478bdstevel@tonic-gateuc_walk_step(mdb_walk_state_t *wsp)
3267c478bdstevel@tonic-gate{
3277c478bdstevel@tonic-gate	uintptr_t addr = wsp->walk_addr;
3287c478bdstevel@tonic-gate	ucontext_t uc;
3297c478bdstevel@tonic-gate
330892ad16Toomas Soome	if (addr == 0)
3317c478bdstevel@tonic-gate		return (WALK_DONE);
3327c478bdstevel@tonic-gate
3337c478bdstevel@tonic-gate	if (mdb_vread(&uc, sizeof (uc), addr) != sizeof (uc)) {
3347c478bdstevel@tonic-gate		mdb_warn("failed to read ucontext at %p", addr);
3357c478bdstevel@tonic-gate		return (WALK_ERR);
3367c478bdstevel@tonic-gate	}
3377c478bdstevel@tonic-gate
3387c478bdstevel@tonic-gate	wsp->walk_addr = (uintptr_t)uc.uc_link;
3397c478bdstevel@tonic-gate	return (wsp->walk_callback(addr, &uc, wsp->walk_cbdata));
3407c478bdstevel@tonic-gate}
3417c478bdstevel@tonic-gate
3427c478bdstevel@tonic-gatestatic int
3437c478bdstevel@tonic-gateoldc_walk_init(mdb_walk_state_t *wsp)
3447c478bdstevel@tonic-gate{
3457c478bdstevel@tonic-gate	ssize_t nbytes = mdb_get_xdata("lwpstatus", NULL, 0);
3467c478bdstevel@tonic-gate
3477c478bdstevel@tonic-gate	if (nbytes <= 0) {
3487c478bdstevel@tonic-gate		mdb_warn("lwpstatus information not available");
3497c478bdstevel@tonic-gate		return (WALK_ERR);
3507c478bdstevel@tonic-gate	}
3517c478bdstevel@tonic-gate
352892ad16Toomas Soome	if (wsp->walk_addr != 0) {
3537c478bdstevel@tonic-gate		mdb_warn("walker only supports global walk\n");
3547c478bdstevel@tonic-gate		return (WALK_ERR);
3557c478bdstevel@tonic-gate	}
3567c478bdstevel@tonic-gate
3577c478bdstevel@tonic-gate	wsp->walk_addr = nbytes; /* Use walk_addr to track size */
3587c478bdstevel@tonic-gate	wsp->walk_data = mdb_alloc(nbytes, UM_SLEEP);
3597c478bdstevel@tonic-gate
3607c478bdstevel@tonic-gate	if (mdb_get_xdata("lwpstatus", wsp->walk_data, nbytes) != nbytes) {
3617c478bdstevel@tonic-gate		mdb_warn("failed to read lwpstatus information");
3627c478bdstevel@tonic-gate		mdb_free(wsp->walk_data, nbytes);
3637c478bdstevel@tonic-gate		return (WALK_ERR);
3647c478bdstevel@tonic-gate	}
3657c478bdstevel@tonic-gate
3667c478bdstevel@tonic-gate	wsp->walk_arg = wsp->walk_data; /* Use walk_arg to track pointer */
3677c478bdstevel@tonic-gate	return (WALK_NEXT);
3687c478bdstevel@tonic-gate}
3697c478bdstevel@tonic-gate
3707c478bdstevel@tonic-gatestatic int
3717c478bdstevel@tonic-gateoldc_walk_step(mdb_walk_state_t *wsp)
3727c478bdstevel@tonic-gate{
3737c478bdstevel@tonic-gate	const lwpstatus_t *lsp, *end;
3747c478bdstevel@tonic-gate
3757c478bdstevel@tonic-gate	end = (const lwpstatus_t *)((uintptr_t)wsp->walk_data + wsp->walk_addr);
3767c478bdstevel@tonic-gate	lsp = wsp->walk_arg;
3777c478bdstevel@tonic-gate
3787c478bdstevel@tonic-gate	wsp->walk_arg = (void *)(lsp + 1);
3797c478bdstevel@tonic-gate
3807c478bdstevel@tonic-gate	if (lsp < end) {
3817c478bdstevel@tonic-gate		uintptr_t addr = lsp->pr_oldcontext;
3827c478bdstevel@tonic-gate		ucontext_t uc;
3837c478bdstevel@tonic-gate
384892ad16Toomas Soome		if (addr == 0)
3857c478bdstevel@tonic-gate			return (WALK_NEXT);
3867c478bdstevel@tonic-gate
3877c478bdstevel@tonic-gate		if (mdb_vread(&uc, sizeof (uc), addr) != sizeof (uc)) {
3887c478bdstevel@tonic-gate			mdb_warn("failed to read ucontext at %p", addr);
3897c478bdstevel@tonic-gate			return (WALK_NEXT);
3907c478bdstevel@tonic-gate		}
3917c478bdstevel@tonic-gate
3927c478bdstevel@tonic-gate		return (wsp->walk_callback(addr, &uc, wsp->walk_cbdata));
3937c478bdstevel@tonic-gate	}
3947c478bdstevel@tonic-gate
3957c478bdstevel@tonic-gate	return (WALK_DONE);
3967c478bdstevel@tonic-gate}
3977c478bdstevel@tonic-gate
3987c478bdstevel@tonic-gatestatic void
3997c478bdstevel@tonic-gateoldc_walk_fini(mdb_walk_state_t *wsp)
4007c478bdstevel@tonic-gate{
4017c478bdstevel@tonic-gate	mdb_free(wsp->walk_data, wsp->walk_addr); /* walk_addr has size */
4027c478bdstevel@tonic-gate}
4037c478bdstevel@tonic-gate
4047c478bdstevel@tonic-gate/*
4057c478bdstevel@tonic-gate * ==================== threads ==========================
4067c478bdstevel@tonic-gate * These are the interfaces that used to require libthread.
4077c478bdstevel@tonic-gate * Now, libthread has been folded into libc.
4087c478bdstevel@tonic-gate * =======================================================
4097c478bdstevel@tonic-gate */
4107c478bdstevel@tonic-gate
4117c478bdstevel@tonic-gate/*
4127c478bdstevel@tonic-gate * prt_addr() is called up to three times to generate arguments for
4137c478bdstevel@tonic-gate * one call to mdb_printf().  We must return at least three different
4147c478bdstevel@tonic-gate * pointers to static storage for consecutive calls to prt_addr().
4157c478bdstevel@tonic-gate */
4167c478bdstevel@tonic-gatestatic const char *
4177c478bdstevel@tonic-gateprt_addr(void *addr, int pad)
4187c478bdstevel@tonic-gate{
4197c478bdstevel@tonic-gate	static char buffer[4][24];
4207c478bdstevel@tonic-gate	static int ix = 0;
4217c478bdstevel@tonic-gate	char *buf;
4227c478bdstevel@tonic-gate
4237c478bdstevel@tonic-gate	if (ix == 4)	/* use buffers in sequence: 0, 1, 2, 3 */
4247c478bdstevel@tonic-gate		ix = 0;
4257c478bdstevel@tonic-gate	buf = buffer[ix++];
4267c478bdstevel@tonic-gate	if (addr == NULL)
4277c478bdstevel@tonic-gate		return (pad? "<NULL>               " : "<NULL>");
4287c478bdstevel@tonic-gate	else {
4297c478bdstevel@tonic-gate#ifdef _LP64
4307c478bdstevel@tonic-gate		(void) mdb_snprintf(buf, sizeof (buffer[0]), "0x%016lx", addr);
4317c478bdstevel@tonic-gate		if (pad)
4327c478bdstevel@tonic-gate			(void) strcpy(buf + 18, "   ");
4337c478bdstevel@tonic-gate#else
4347c478bdstevel@tonic-gate		(void) mdb_snprintf(buf, sizeof (buffer[0]), "0x%08lx", addr);
4357c478bdstevel@tonic-gate		if (pad)
4367c478bdstevel@tonic-gate			(void) strcpy(buf + 10, "           ");
4377c478bdstevel@tonic-gate#endif	/* _LP64 */
4387c478bdstevel@tonic-gate		return (buf);
4397c478bdstevel@tonic-gate	}
4407c478bdstevel@tonic-gate}
4417c478bdstevel@tonic-gate
4427c478bdstevel@tonic-gate#define	HD(str)		mdb_printf("           " str "\n")
4437c478bdstevel@tonic-gate#define	OFFSTR		"+0x%-7lx "
4447c478bdstevel@tonic-gate#define	OFFSET(member)	((size_t)OFFSETOF(ulwp_t, member))
4457c478bdstevel@tonic-gate
4467c478bdstevel@tonic-gate/*ARGSUSED*/
4477c478bdstevel@tonic-gatestatic int
4487c478bdstevel@tonic-gated_ulwp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4497c478bdstevel@tonic-gate{
4507c478bdstevel@tonic-gate	ulwp_t ulwp;
4517c478bdstevel@tonic-gate
4527c478bdstevel@tonic-gate	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
4537c478bdstevel@tonic-gate		return (DCMD_USAGE);
4547c478bdstevel@tonic-gate
4557c478bdstevel@tonic-gate	if (mdb_vread(&ulwp, sizeof (ulwp), addr) != sizeof (ulwp) &&
4567c478bdstevel@tonic-gate	    (bzero(&ulwp, sizeof (ulwp)),
4577c478bdstevel@tonic-gate	    mdb_vread(&ulwp, REPLACEMENT_SIZE, addr)) != REPLACEMENT_SIZE) {
4587c478bdstevel@tonic-gate		mdb_warn("failed to read ulwp at 0x%p", addr);
4597c478bdstevel@tonic-gate		return (DCMD_ERR);
4607c478bdstevel@tonic-gate	}
4617c478bdstevel@tonic-gate
4627c478bdstevel@tonic-gate	mdb_printf("%#a\n", addr);
4637c478bdstevel@tonic-gate
4647c478bdstevel@tonic-gate	HD("self                  uberdata");
4657c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%s %s\n",
4668cd4554raf	    OFFSET(ul_self),
4678cd4554raf	    prt_addr(ulwp.ul_self, 1),
4688cd4554raf	    prt_addr(ulwp.ul_uberdata, 0));
4697c478bdstevel@tonic-gate
4707c478bdstevel@tonic-gate	HD("tlsent                ntlsent");
4717c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%s %ld\n",
4728cd4554raf	    OFFSET(ul_tlsent),
4738cd4554raf	    prt_addr(ulwp.ul_tlsent, 1),
4748cd4554raf	    ulwp.ul_ntlsent);
4757c478bdstevel@tonic-gate
4767c478bdstevel@tonic-gate	HD("forw                  back                  next");
4777c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%s %s %s\n",
4788cd4554raf	    OFFSET(ul_forw),
4798cd4554raf	    prt_addr(ulwp.ul_forw, 1),
4808cd4554raf	    prt_addr(ulwp.ul_back, 1),
4818cd4554raf	    prt_addr(ulwp.ul_next, 0));
4827c478bdstevel@tonic-gate
4837c478bdstevel@tonic-gate	HD("hash                  rval                  stk");
4847c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%s %s %s\n",
4858cd4554raf	    OFFSET(ul_hash),
4868cd4554raf	    prt_addr(ulwp.ul_hash, 1),
4878cd4554raf	    prt_addr(ulwp.ul_rval, 1),
4888cd4554raf	    prt_addr(ulwp.ul_stk, 0));
4897c478bdstevel@tonic-gate
4907c478bdstevel@tonic-gate	HD("mapsiz     guardsize  stktop                stksiz");
4917c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%-10ld %-10ld %s %ld\n",
4928cd4554raf	    OFFSET(ul_mapsiz),
4938cd4554raf	    ulwp.ul_mapsiz,
4948cd4554raf	    ulwp.ul_guardsize,
4958cd4554raf	    prt_addr((void *)ulwp.ul_stktop, 1),
4968cd4554raf	    ulwp.ul_stksiz);
4977c478bdstevel@tonic-gate
4987c478bdstevel@tonic-gate	HD("ustack.ss_sp          ustack.ss_size        ustack.ss_flags");
4997c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%s %-21ld %s\n",
5008cd4554raf	    OFFSET(ul_ustack.ss_sp),
5018cd4554raf	    prt_addr(ulwp.ul_ustack.ss_sp, 1),
5028cd4554raf	    ulwp.ul_ustack.ss_size,
5038cd4554raf	    stack_flags(&ulwp.ul_ustack));
5047c478bdstevel@tonic-gate
505d4204c8raf	HD("ix         lwpid      pri        epri       policy     cid");
5067c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n",
5078cd4554raf	    OFFSET(ul_ix),
5088cd4554raf	    ulwp.ul_ix,
5098cd4554raf	    ulwp.ul_lwpid,
5108cd4554raf	    ulwp.ul_pri,
5118cd4554raf	    ulwp.ul_epri,
5128cd4554raf	    ulwp.ul_policy,
5138cd4554raf	    ulwp.ul_cid);
5147c478bdstevel@tonic-gate
5157c478bdstevel@tonic-gate	HD("cursig     pleasestop stop       signalled  dead       unwind");
5167c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%-10d ",
5178cd4554raf	    OFFSET(ul_cursig),
5188cd4554raf	    ulwp.ul_cursig);
5197c478bdstevel@tonic-gate	mdb_printf(ulwp.ul_pleasestop? "0x%-8x " : "%-10d ",
5208cd4554raf	    ulwp.ul_pleasestop);
5217c478bdstevel@tonic-gate	mdb_printf(ulwp.ul_stop? "0x%-8x " : "%-10d ",
5228cd4554raf	    ulwp.ul_stop);
5237c478bdstevel@tonic-gate	mdb_printf("%-10d %-10d %d\n",
5248cd4554raf	    ulwp.ul_signalled,
5258cd4554raf	    ulwp.ul_dead,
5268cd4554raf	    ulwp.ul_unwind);
5277c478bdstevel@tonic-gate
5283470957raf	HD("detached   writer     stopping   can'prolog preempt    savpreempt");
5297c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n",
5308cd4554raf	    OFFSET(ul_detached),
5318cd4554raf	    ulwp.ul_detached,
5328cd4554raf	    ulwp.ul_writer,
5338cd4554raf	    ulwp.ul_stopping,
5348cd4554raf	    ulwp.ul_cancel_prologue,
5358cd4554raf	    ulwp.ul_preempt,
5368cd4554raf	    ulwp.ul_savpreempt);
5377c478bdstevel@tonic-gate
5387c478bdstevel@tonic-gate	HD("sigsuspend main       fork       primarymap m'spinners d'noreserv");
5397c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n",
5408cd4554raf	    OFFSET(ul_sigsuspend),
5418cd4554raf	    ulwp.ul_sigsuspend,
5428cd4554raf	    ulwp.ul_main,
5438cd4554raf	    ulwp.ul_fork,
5448cd4554raf	    ulwp.ul_primarymap,
5458cd4554raf	    ulwp.ul_max_spinners,
5468cd4554raf	    ulwp.ul_door_noreserve);
5477c478bdstevel@tonic-gate
548d4204c8raf	HD("queue_fifo c'w'defer  e'detect'  async_safe rt         rtqueued");
5497c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n",
5508cd4554raf	    OFFSET(ul_queue_fifo),
5518cd4554raf	    ulwp.ul_queue_fifo,
5528cd4554raf	    ulwp.ul_cond_wait_defer,
5538cd4554raf	    ulwp.ul_error_detection,
5548cd4554raf	    ulwp.ul_async_safe,
5558cd4554raf	    ulwp.ul_rt,
5568cd4554raf	    ulwp.ul_rtqueued);
5577c478bdstevel@tonic-gate
5587c5714fraf	HD("misaligned adapt'spin queue_spin critical   sigdefer   vfork");
5597c5714fraf	mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n",
5607c5714fraf	    OFFSET(ul_misaligned),
5617c5714fraf	    ulwp.ul_misaligned,
5628cd4554raf	    ulwp.ul_adaptive_spin,
5638cd4554raf	    ulwp.ul_queue_spin,
5648cd4554raf	    ulwp.ul_critical,
5658cd4554raf	    ulwp.ul_sigdefer,
5668cd4554raf	    ulwp.ul_vfork);
5677c478bdstevel@tonic-gate
5687c478bdstevel@tonic-gate	HD("cancelable c'pending  c'disabled c'async    save_async mutator");
5697c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n",
5708cd4554raf	    OFFSET(ul_cancelable),
5718cd4554raf	    ulwp.ul_cancelable,
5728cd4554raf	    ulwp.ul_cancel_pending,
5738cd4554raf	    ulwp.ul_cancel_disabled,
5748cd4554raf	    ulwp.ul_cancel_async,
5758cd4554raf	    ulwp.ul_save_async,
5768cd4554raf	    ulwp.ul_mutator);
5777c478bdstevel@tonic-gate
5787c478bdstevel@tonic-gate	HD("created    replace    nocancel   errno      errnop");
5797c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %s\n",
5808cd4554raf	    OFFSET(ul_created),
5818cd4554raf	    ulwp.ul_created,
5828cd4554raf	    ulwp.ul_replace,
5838cd4554raf	    ulwp.ul_nocancel,
5848cd4554raf	    ulwp.ul_errno,
5858cd4554raf	    prt_addr(ulwp.ul_errnop, 0));
5867c478bdstevel@tonic-gate
5877c478bdstevel@tonic-gate	HD("clnup_hdr             schedctl_called       schedctl");
5887c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%s %s %s\n",
5898cd4554raf	    OFFSET(ul_clnup_hdr),
5908cd4554raf	    prt_addr(ulwp.ul_clnup_hdr, 1),
5918cd4554raf	    prt_addr(ulwp.ul_schedctl_called, 1),
5928cd4554raf	    prt_addr((void *)ulwp.ul_schedctl, 0));
5937c478bdstevel@tonic-gate
594a574db8raf	HD("bindflags  libc_locks stsd                  &ftsd");
5957c478bdstevel@tonic-gate	mdb_printf(OFFSTR,
5968cd4554raf	    OFFSET(ul_bindflags));
5977c478bdstevel@tonic-gate	mdb_printf(ulwp.ul_bindflags? "0x%-8x " : "%-10d ",
5988cd4554raf	    ulwp.ul_bindflags);
599a574db8raf	mdb_printf("%-10d ", ulwp.ul_libc_locks);
6007c478bdstevel@tonic-gate	mdb_printf("%s %s\n",
6018cd4554raf	    prt_addr(ulwp.ul_stsd, 1),
6028cd4554raf	    prt_addr((void *)(addr + OFFSET(ul_ftsd[0])), 0));
6037c478bdstevel@tonic-gate
6047c478bdstevel@tonic-gate	HD("eventmask[0..1]       eventnum              eventdata");
6057c478bdstevel@tonic-gate	mdb_printf(OFFSTR "0x%08x 0x%08x %-21d %s\n",
6068cd4554raf	    OFFSET(ul_td_evbuf.eventmask.event_bits[0]),
6078cd4554raf	    ulwp.ul_td_evbuf.eventmask.event_bits[0],
6088cd4554raf	    ulwp.ul_td_evbuf.eventmask.event_bits[1],
6098cd4554raf	    ulwp.ul_td_evbuf.eventnum,
6108cd4554raf	    prt_addr(ulwp.ul_td_evbuf.eventdata, 0));
6117c478bdstevel@tonic-gate
612e54ab87Roger A. Faulkner	HD("td'enable  sync'reg   qtype      cv_wake    rtld       usropts");
613e54ab87Roger A. Faulkner	mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d ",
6148cd4554raf	    OFFSET(ul_td_events_enable),
6158cd4554raf	    ulwp.ul_td_events_enable,
6168cd4554raf	    ulwp.ul_sync_obj_reg,
6178cd4554raf	    ulwp.ul_qtype,
618e54ab87Roger A. Faulkner	    ulwp.ul_cv_wake,
619e54ab87Roger A. Faulkner	    ulwp.ul_rtld);
6207c478bdstevel@tonic-gate	mdb_printf(ulwp.ul_usropts? "0x%x\n" : "%d\n",
6218cd4554raf	    ulwp.ul_usropts);
6227c478bdstevel@tonic-gate
6237c478bdstevel@tonic-gate	HD("startpc               startarg              wchan");
6247c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%s %s %s\n",
6258cd4554raf	    OFFSET(ul_startpc),
6268cd4554raf	    prt_addr((void *)ulwp.ul_startpc, 1),
6278cd4554raf	    prt_addr(ulwp.ul_startarg, 1),
6288cd4554raf	    prt_addr(ulwp.ul_wchan, 0));
6297c478bdstevel@tonic-gate
6307c478bdstevel@tonic-gate	HD("link                  sleepq                cvmutex");
6317c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%s %s %s\n",
6328cd4554raf	    OFFSET(ul_link),
6338cd4554raf	    prt_addr(ulwp.ul_link, 1),
6348cd4554raf	    prt_addr(ulwp.ul_sleepq, 1),
6358cd4554raf	    prt_addr(ulwp.ul_cvmutex, 0));
6367c478bdstevel@tonic-gate
637d4204c8raf	HD("mxchain               save_state");
638d4204c8raf	mdb_printf(OFFSTR "%s %d\n",
6398cd4554raf	    OFFSET(ul_mxchain),
6408cd4554raf	    prt_addr(ulwp.ul_mxchain, 1),
6418cd4554raf	    ulwp.ul_save_state);
6427c478bdstevel@tonic-gate
643883492draf	HD("rdlockcnt             rd_rwlock             rd_count");
644883492draf	mdb_printf(OFFSTR "%-21d %s %d\n",
6458cd4554raf	    OFFSET(ul_rdlockcnt),
6468cd4554raf	    ulwp.ul_rdlockcnt,
6478cd4554raf	    prt_addr(ulwp.ul_readlock.single.rd_rwlock, 1),
6488cd4554raf	    ulwp.ul_readlock.single.rd_count);
649883492draf
650883492draf	HD("heldlockcnt           heldlocks             tpdp");
651883492draf	mdb_printf(OFFSTR "%-21d %s %s\n",
6528cd4554raf	    OFFSET(ul_heldlockcnt),
6538cd4554raf	    ulwp.ul_heldlockcnt,
6548cd4554raf	    prt_addr(ulwp.ul_heldlocks.single, 1),
6558cd4554raf	    prt_addr(ulwp.ul_tpdp, 0));
6567c478bdstevel@tonic-gate
6577c478bdstevel@tonic-gate	HD("siglink               s'l'spin   s'l'spin2  s'l'sleep  s'l'wakeup");
658d4204c8raf	mdb_printf(OFFSTR "%s %-10d %-10d %-10d %d\n",
6598cd4554raf	    OFFSET(ul_siglink),
6608cd4554raf	    prt_addr(ulwp.ul_siglink, 1),
6618cd4554raf	    ulwp.ul_spin_lock_spin,
6628cd4554raf	    ulwp.ul_spin_lock_spin2,
6638cd4554raf	    ulwp.ul_spin_lock_sleep,
6648cd4554raf	    ulwp.ul_spin_lock_wakeup);
6657c478bdstevel@tonic-gate
666d4204c8raf	HD("&queue_root           rtclassid  pilocks");
667d4204c8raf	mdb_printf(OFFSTR "%s %-10d %d\n",
6688cd4554raf	    OFFSET(ul_queue_root),
6698cd4554raf	    prt_addr((void *)(addr + OFFSET(ul_queue_root)), 1),
6708cd4554raf	    ulwp.ul_rtclassid,
6718cd4554raf	    ulwp.ul_pilocks);
672d4204c8raf
6737c478bdstevel@tonic-gate	/*
6747c478bdstevel@tonic-gate	 * The remainder of the ulwp_t structure
6757c478bdstevel@tonic-gate	 * is invalid if this is a replacement.
6767c478bdstevel@tonic-gate	 */
6777c478bdstevel@tonic-gate	if (ulwp.ul_replace)
6787c478bdstevel@tonic-gate		return (DCMD_OK);
6797c478bdstevel@tonic-gate
6807c478bdstevel@tonic-gate	HD("sigmask[0..3]");
6817c478bdstevel@tonic-gate	mdb_printf(OFFSTR "0x%08x 0x%08x 0x%08x 0x%08x\n",
6828cd4554raf	    OFFSET(ul_sigmask.__sigbits[0]),
6838cd4554raf	    ulwp.ul_sigmask.__sigbits[0],
6848cd4554raf	    ulwp.ul_sigmask.__sigbits[1],
6858cd4554raf	    ulwp.ul_sigmask.__sigbits[2],
6868cd4554raf	    ulwp.ul_sigmask.__sigbits[3]);
6877c478bdstevel@tonic-gate
6887c478bdstevel@tonic-gate	HD("tmpmask[0..3]");
6897c478bdstevel@tonic-gate	mdb_printf(OFFSTR "0x%08x 0x%08x 0x%08x 0x%08x\n",
6908cd4554raf	    OFFSET(ul_tmpmask.__sigbits[0]),
6918cd4554raf	    ulwp.ul_tmpmask.__sigbits[0],
6928cd4554raf	    ulwp.ul_tmpmask.__sigbits[1],
6938cd4554raf	    ulwp.ul_tmpmask.__sigbits[2],
6948cd4554raf	    ulwp.ul_tmpmask.__sigbits[3]);
6957c478bdstevel@tonic-gate
6967c478bdstevel@tonic-gate	HD("&siginfo              &spinlock             &fpuenv");
6977c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%s %s %s\n",
6988cd4554raf	    OFFSET(ul_siginfo),
6998cd4554raf	    prt_addr((void *)(addr + OFFSET(ul_siginfo)), 1),
7008cd4554raf	    prt_addr((void *)(addr + OFFSET(ul_spinlock)), 1),
7018cd4554raf	    prt_addr((void *)(addr + OFFSET(ul_fpuenv)), 0));
7027c478bdstevel@tonic-gate
7034f364e7Robert Mustacchi	HD("tmem.size             &tmem.roots");
7044f364e7Robert Mustacchi	mdb_printf(OFFSTR "%-21H %s\n",
7054f364e7Robert Mustacchi	    OFFSET(ul_tmem),
7064f364e7Robert Mustacchi	    ulwp.ul_tmem.tm_size,
7074f364e7Robert Mustacchi	    prt_addr((void *)(addr + OFFSET(ul_tmem) + sizeof (size_t)), 0));
7084f364e7Robert Mustacchi
7097c478bdstevel@tonic-gate	return (DCMD_OK);
7107c478bdstevel@tonic-gate}
7117c478bdstevel@tonic-gate
7127c478bdstevel@tonic-gate/*
7137c478bdstevel@tonic-gate * Get the address of the unique uberdata_t structure.
7147c478bdstevel@tonic-gate */
7157c478bdstevel@tonic-gatestatic uintptr_t
7167c478bdstevel@tonic-gateuberdata_addr(void)
7177c478bdstevel@tonic-gate{
7187c478bdstevel@tonic-gate	uintptr_t uaddr;
7197c478bdstevel@tonic-gate	uintptr_t addr;
7207c478bdstevel@tonic-gate	GElf_Sym sym;
7217c478bdstevel@tonic-gate
7227c478bdstevel@tonic-gate	if (mdb_lookup_by_obj("libc.so.1", "_tdb_bootstrap", &sym) != 0) {
7237c478bdstevel@tonic-gate		mdb_warn("cannot find libc.so.1`_tdb_bootstrap");
724892ad16Toomas Soome		return (0);
7257c478bdstevel@tonic-gate	}
7267c478bdstevel@tonic-gate	if (mdb_vread(&addr, sizeof (addr), sym.st_value) == sizeof (addr) &&
727892ad16Toomas Soome	    addr != 0 &&
7287c478bdstevel@tonic-gate	    mdb_vread(&uaddr, sizeof (uaddr), addr) == sizeof (uaddr) &&
729892ad16Toomas Soome	    uaddr != 0) {
7307c478bdstevel@tonic-gate		return (uaddr);
7317c478bdstevel@tonic-gate	}
7327c478bdstevel@tonic-gate	if (mdb_lookup_by_obj("libc.so.1", "_uberdata", &sym) != 0) {
7337c478bdstevel@tonic-gate		mdb_warn("cannot find libc.so.1`_uberdata");
734892ad16Toomas Soome		return (0);
7357c478bdstevel@tonic-gate	}
7367c478bdstevel@tonic-gate	return ((uintptr_t)sym.st_value);
7377c478bdstevel@tonic-gate}
7387c478bdstevel@tonic-gate
7397c478bdstevel@tonic-gate#undef OFFSET
7407c478bdstevel@tonic-gate#define	OFFSET(member)	((size_t)OFFSETOF(uberdata_t, member))
7417c478bdstevel@tonic-gate
7427c478bdstevel@tonic-gate/*ARGSUSED*/
7437c478bdstevel@tonic-gatestatic int
7447c478bdstevel@tonic-gated_uberdata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
7457c478bdstevel@tonic-gate{
7467c478bdstevel@tonic-gate	uberdata_t uberdata;
7477c478bdstevel@tonic-gate	int i;
7487c478bdstevel@tonic-gate
7497c478bdstevel@tonic-gate	if (argc != 0)
7507c478bdstevel@tonic-gate		return (DCMD_USAGE);
751892ad16Toomas Soome	if (!(flags & DCMD_ADDRSPEC) && (addr = uberdata_addr()) == 0)
7527c478bdstevel@tonic-gate		return (DCMD_ERR);
7537c478bdstevel@tonic-gate
7547c478bdstevel@tonic-gate	if (mdb_vread(&uberdata, sizeof (uberdata), addr) !=
7557c478bdstevel@tonic-gate	    sizeof (uberdata)) {
7567c478bdstevel@tonic-gate		mdb_warn("failed to read uberdata at 0x%p", addr);
7577c478bdstevel@tonic-gate		return (DCMD_ERR);
7587c478bdstevel@tonic-gate	}
7597c478bdstevel@tonic-gate
7607c478bdstevel@tonic-gate	mdb_printf("%#a\n", addr);
7617c478bdstevel@tonic-gate
7628cd4554raf	HD("&link_lock            &ld_lock              &fork_lock");
7637c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%s %s %s\n",
7648cd4554raf	    OFFSET(link_lock),
7658cd4554raf	    prt_addr((void *)(addr + OFFSET(link_lock)), 1),
7668cd4554raf	    prt_addr((void *)(addr + OFFSET(ld_lock)), 1),
7678cd4554raf	    prt_addr((void *)(addr + OFFSET(fork_lock)), 0));
7687c478bdstevel@tonic-gate
7698cd4554raf	HD("&atfork_lock          &callout_lock         &tdb_hash_lock");
7707c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%s %s %s\n",
7718cd4554raf	    OFFSET(atfork_lock),
7728cd4554raf	    prt_addr((void *)(addr + OFFSET(atfork_lock)), 1),
7738cd4554raf	    prt_addr((void *)(addr + OFFSET(callout_lock)), 1),
7748cd4554raf	    prt_addr((void *)(addr + OFFSET(tdb_hash_lock)), 0));
7758cd4554raf
7768cd4554raf	HD("&tdb_hash_lock_stats  &siguaction[0]");
7778cd4554raf	mdb_printf(OFFSTR "%s %s\n",
7788cd4554raf	    OFFSET(tdb_hash_lock_stats),
7798cd4554raf	    prt_addr((void *)(addr + OFFSET(tdb_hash_lock_stats)), 1),
7808cd4554raf	    prt_addr((void *)(addr + OFFSET(siguaction)), 0));
7817c478bdstevel@tonic-gate
7827c478bdstevel@tonic-gate	HD("&bucket               free_list             chunks");
7837c478bdstevel@tonic-gate	for (i = 0; i < NBUCKETS; i++) {
7847c478bdstevel@tonic-gate		mdb_printf(OFFSTR "%s %s %ld\n",
7858cd4554raf		    OFFSET(bucket[i]),
7868cd4554raf		    prt_addr((void *)(addr + OFFSET(bucket[i])), 1),
7878cd4554raf		    prt_addr(uberdata.bucket[i].free_list, 1),
7888cd4554raf		    uberdata.bucket[i].chunks);
7897c478bdstevel@tonic-gate	}
7907c478bdstevel@tonic-gate
7917c478bdstevel@tonic-gate	HD("&atexit_root          head                  exit_frame_monitor");
7927c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%s %s %s\n",
7938cd4554raf	    OFFSET(atexit_root),
7948cd4554raf	    prt_addr((void *)(addr + OFFSET(atexit_root.exitfns_lock)), 1),
7958cd4554raf	    prt_addr(uberdata.atexit_root.head, 1),
7968cd4554raf	    prt_addr(uberdata.atexit_root.exit_frame_monitor, 0));
7977c478bdstevel@tonic-gate
798fc2512cRobert Mustacchi	HD("&quickexit_root       head");
799fc2512cRobert Mustacchi	mdb_printf(OFFSTR "%s %s\n",
800fc2512cRobert Mustacchi	    OFFSET(quickexit_root),
801fc2512cRobert Mustacchi	    prt_addr((void *)(addr + OFFSET(quickexit_root.exitfns_lock)), 1),
802fc2512cRobert Mustacchi	    prt_addr(uberdata.quickexit_root.head, 0));
803fc2512cRobert Mustacchi
804fc2512cRobert Mustacchi
8057c478bdstevel@tonic-gate	HD("&tsd_metadata         tsdm_nkeys tsdm_nused tsdm_destro");
8067c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%s %-10d %-10d %s\n",
8078cd4554raf	    OFFSET(tsd_metadata),
8088cd4554raf	    prt_addr((void *)(addr + OFFSET(tsd_metadata.tsdm_lock)), 1),
8098cd4554raf	    uberdata.tsd_metadata.tsdm_nkeys,
8108cd4554raf	    uberdata.tsd_metadata.tsdm_nused,
8118cd4554raf	    prt_addr((void *)uberdata.tsd_metadata.tsdm_destro, 0));
8127c478bdstevel@tonic-gate
8137c478bdstevel@tonic-gate	HD("&tls_metadata         tls_modinfo.data      tls_modinfo.size");
8147c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%s %s %ld\n",
8158cd4554raf	    OFFSET(tls_metadata),
8168cd4554raf	    prt_addr((void *)(addr + OFFSET(tls_metadata.tls_lock)), 1),
8178cd4554raf	    prt_addr(uberdata.tls_metadata.tls_modinfo.tls_data, 1),
8188cd4554raf	    uberdata.tls_metadata.tls_modinfo.tls_size);
8197c478bdstevel@tonic-gate
8207c478bdstevel@tonic-gate	HD("                      static_tls.data       static_tls.size");
8217c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%s %s %ld\n",
8228cd4554raf	    OFFSET(tls_metadata.static_tls),
8238cd4554raf	    "                     ",
8248cd4554raf	    prt_addr(uberdata.tls_metadata.static_tls.tls_data, 1),
8258cd4554raf	    uberdata.tls_metadata.static_tls.tls_size);
8267c478bdstevel@tonic-gate
8277c478bdstevel@tonic-gate	HD("primary_ma bucket_ini uflags.mt  uflags.pad uflags.trs uflags.ted");
8287c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n",
8298cd4554raf	    OFFSET(primary_map),
8308cd4554raf	    uberdata.primary_map,
8318cd4554raf	    uberdata.bucket_init,
8328cd4554raf	    uberdata.uberflags.uf_x.x_mt,
8338cd4554raf	    uberdata.uberflags.uf_x.x_pad,
8348cd4554raf	    uberdata.uberflags.uf_x.x_tdb_register_sync,
8358cd4554raf	    uberdata.uberflags.uf_x.x_thread_error_detection);
8367c478bdstevel@tonic-gate
8377c478bdstevel@tonic-gate	HD("queue_head            thr_hash_table        hash_size  hash_mask");
8387c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%s %s %-10d 0x%x\n",
8398cd4554raf	    OFFSET(queue_head),
8408cd4554raf	    prt_addr(uberdata.queue_head, 1),
8418cd4554raf	    prt_addr(uberdata.thr_hash_table, 1),
8428cd4554raf	    uberdata.hash_size,
8438cd4554raf	    uberdata.hash_mask);
8447c478bdstevel@tonic-gate
8457c478bdstevel@tonic-gate	HD("ulwp_one              all_lwps              all_zombies");
8467c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%s %s %s\n",
8478cd4554raf	    OFFSET(ulwp_one),
8488cd4554raf	    prt_addr(uberdata.ulwp_one, 1),
8498cd4554raf	    prt_addr(uberdata.all_lwps, 1),
8508cd4554raf	    prt_addr(uberdata.all_zombies, 0));
8517c478bdstevel@tonic-gate
8527c478bdstevel@tonic-gate	HD("nthreads   nzombies   ndaemons   pid        sigacthandler");
8537c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %s\n",
8548cd4554raf	    OFFSET(nthreads),
8558cd4554raf	    uberdata.nthreads,
8568cd4554raf	    uberdata.nzombies,
8578cd4554raf	    uberdata.ndaemons,
8588cd4554raf	    (int)uberdata.pid,
8598cd4554raf	    prt_addr((void *)uberdata.sigacthandler, 0));
8607c478bdstevel@tonic-gate
8617c478bdstevel@tonic-gate	HD("lwp_stacks            lwp_laststack         nfreestack stk_cache");
8627c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%s %s %-10d %d\n",
8638cd4554raf	    OFFSET(lwp_stacks),
8648cd4554raf	    prt_addr(uberdata.lwp_stacks, 1),
8658cd4554raf	    prt_addr(uberdata.lwp_laststack, 1),
8668cd4554raf	    uberdata.nfreestack,
8678cd4554raf	    uberdata.thread_stack_cache);
8687c478bdstevel@tonic-gate
8698cd4554raf	HD("ulwp_freelist         ulwp_lastfree         ulwp_replace_free");
8708cd4554raf	mdb_printf(OFFSTR "%s %s %s\n",
8718cd4554raf	    OFFSET(ulwp_freelist),
8728cd4554raf	    prt_addr(uberdata.ulwp_freelist, 1),
8738cd4554raf	    prt_addr(uberdata.ulwp_lastfree, 1),
8748cd4554raf	    prt_addr(uberdata.ulwp_replace_free, 0));
875883492draf
87609ce0d4Roger A. Faulkner	HD("ulwp_replace_last     atforklist");
87709ce0d4Roger A. Faulkner	mdb_printf(OFFSTR "%s %s\n",
8788cd4554raf	    OFFSET(ulwp_replace_last),
8798cd4554raf	    prt_addr(uberdata.ulwp_replace_last, 1),
88009ce0d4Roger A. Faulkner	    prt_addr(uberdata.atforklist, 0));
88109ce0d4Roger A. Faulkner
88223a1cceRoger A. Faulkner	HD("robustlocks           robustlist            progname");
88323a1cceRoger A. Faulkner	mdb_printf(OFFSTR "%s %s %s\n",
88409ce0d4Roger A. Faulkner	    OFFSET(robustlocks),
88509ce0d4Roger A. Faulkner	    prt_addr(uberdata.robustlocks, 1),
88623a1cceRoger A. Faulkner	    prt_addr(uberdata.robustlist, 1),
88723a1cceRoger A. Faulkner	    prt_addr(uberdata.progname, 0));
8887c478bdstevel@tonic-gate
8897c478bdstevel@tonic-gate	HD("tdb_bootstrap         tdb_sync_addr_hash    tdb_'count tdb_'fail");
8907c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%s %s %-10d %d\n",
8918cd4554raf	    OFFSET(tdb_bootstrap),
8928cd4554raf	    prt_addr(uberdata.tdb_bootstrap, 1),
8938cd4554raf	    prt_addr(uberdata.tdb.tdb_sync_addr_hash, 1),
8948cd4554raf	    uberdata.tdb.tdb_register_count,
8958cd4554raf	    uberdata.tdb.tdb_hash_alloc_failed);
8967c478bdstevel@tonic-gate
8977c478bdstevel@tonic-gate	HD("tdb_sync_addr_free    tdb_sync_addr_last    tdb_sync_alloc");
8987c478bdstevel@tonic-gate	mdb_printf(OFFSTR "%s %s %ld\n",
8998cd4554raf	    OFFSET(tdb.tdb_sync_addr_free),
9008cd4554raf	    prt_addr(uberdata.tdb.tdb_sync_addr_free, 1),
9018cd4554raf	    prt_addr(uberdata.tdb.tdb_sync_addr_last, 1),
9028cd4554raf	    uberdata.tdb.tdb_sync_alloc);
9037c478bdstevel@tonic-gate
9047c478bdstevel@tonic-gate	HD("tdb_ev_global_mask    tdb_events");
9057c478bdstevel@tonic-gate	mdb_printf(OFFSTR "0x%08x 0x%08x %s\n",
9068cd4554raf	    OFFSET(tdb.tdb_ev_global_mask),
9078cd4554raf	    uberdata.tdb.tdb_ev_global_mask.event_bits[0],
9088cd4554raf	    uberdata.tdb.tdb_ev_global_mask.event_bits[1],
9098cd4554raf	    prt_addr((void *)uberdata.tdb.tdb_events, 0));
9107c478bdstevel@tonic-gate
9117c478bdstevel@tonic-gate	return (DCMD_OK);
9127c478bdstevel@tonic-gate}
9137c478bdstevel@tonic-gate
9147c478bdstevel@tonic-gatestatic int
9157c478bdstevel@tonic-gateulwp_walk_init(mdb_walk_state_t *wsp)
9167c478bdstevel@tonic-gate{
9177c478bdstevel@tonic-gate	uintptr_t addr = wsp->walk_addr;
9187c478bdstevel@tonic-gate	uintptr_t uber_addr;
919e0ee3ceJason King	int offset;
920e0ee3ceJason King
921e0ee3ceJason King	offset = mdb_ctf_offsetof_by_name("uberdata_t", "all_lwps");
922e0ee3ceJason King	if (offset == -1) {
923e0ee3ceJason King		offset = OFFSETOF(uberdata_t, all_lwps);
924e0ee3ceJason King		mdb_warn("CTF data is missing for uberdata_t; using current "
925e0ee3ceJason King		    "platform's offset for uberdata.all_lwps");
926e0ee3ceJason King	}
9277c478bdstevel@tonic-gate
928892ad16Toomas Soome	if (addr == 0 &&
929892ad16Toomas Soome	    ((uber_addr = uberdata_addr()) == 0 ||
930e0ee3ceJason King	    mdb_vread(&addr, sizeof (addr), uber_addr + offset)
9317c478bdstevel@tonic-gate	    != sizeof (addr))) {
9327c478bdstevel@tonic-gate		mdb_warn("cannot find 'uberdata.all_lwps'");
9337c478bdstevel@tonic-gate		return (WALK_ERR);
9347c478bdstevel@tonic-gate	}
935892ad16Toomas Soome	if (addr == 0)
9367c478bdstevel@tonic-gate		return (WALK_DONE);
9377c478bdstevel@tonic-gate	wsp->walk_addr = addr;
9387c478bdstevel@tonic-gate	wsp->walk_data = (void *)addr;
9397c478bdstevel@tonic-gate	return (WALK_NEXT);
9407c478bdstevel@tonic-gate}
9417c478bdstevel@tonic-gate
9427c478bdstevel@tonic-gatestatic int
9437c478bdstevel@tonic-gateulwp_walk_step(mdb_walk_state_t *wsp)
9447c478bdstevel@tonic-gate{
9457c478bdstevel@tonic-gate	uintptr_t addr = wsp->walk_addr;
9467c478bdstevel@tonic-gate	ulwp_t ulwp;
9477c478bdstevel@tonic-gate
948892ad16Toomas Soome	if (addr == 0)
9497c478bdstevel@tonic-gate		return (WALK_DONE);
9507c478bdstevel@tonic-gate	if (mdb_vread(&ulwp, sizeof (ulwp), addr) != sizeof (ulwp) &&
9517c478bdstevel@tonic-gate	    (bzero(&ulwp, sizeof (ulwp)),
9527c478bdstevel@tonic-gate	    mdb_vread(&ulwp, REPLACEMENT_SIZE, addr)) != REPLACEMENT_SIZE) {
9537c478bdstevel@tonic-gate		mdb_warn("failed to read ulwp at 0x%p", addr);
9547c478bdstevel@tonic-gate		return (WALK_ERR);
9557c478bdstevel@tonic-gate	}
9567c478bdstevel@tonic-gate	/*
9577c478bdstevel@tonic-gate	 * If we have looped around to the beginning
9587c478bdstevel@tonic-gate	 * of the circular linked list, we are done.
9597c478bdstevel@tonic-gate	 */
9607c478bdstevel@tonic-gate	if ((wsp->walk_addr = (uintptr_t)ulwp.ul_forw)
9617c478bdstevel@tonic-gate	    == (uintptr_t)wsp->walk_data)
962892ad16Toomas Soome		wsp->walk_addr = 0;
9637c478bdstevel@tonic-gate	return (wsp->walk_callback(addr, &ulwp, wsp->walk_cbdata));
9647c478bdstevel@tonic-gate}
9657c478bdstevel@tonic-gate
9664a1c243Jonathan Adams/* Avoid classifying NULL pointers as part of the main stack on x86 */
9674a1c243Jonathan Adams#define	MIN_STACK_ADDR		(0x10000ul)
9684a1c243Jonathan Adams
9694a1c243Jonathan Adamsstatic int
9704a1c243Jonathan Adamswhatis_walk_ulwp(uintptr_t addr, const ulwp_t *ulwp, mdb_whatis_t *w)
9714a1c243Jonathan Adams{
9724a1c243Jonathan Adams	uintptr_t cur;
9734a1c243Jonathan Adams	lwpid_t id = ulwp->ul_lwpid;
9744a1c243Jonathan Adams	uintptr_t top, base, size;
9754a1c243Jonathan Adams
9764a1c243Jonathan Adams	while (mdb_whatis_match(w, addr, sizeof (ulwp_t), &cur))
9774a1c243Jonathan Adams		mdb_whatis_report_object(w, cur, addr,
9784a1c243Jonathan Adams		    "allocated as thread %#r's ulwp_t\n", id);
9794a1c243Jonathan Adams
9804a1c243Jonathan Adams	top = (uintptr_t)ulwp->ul_stktop;
9814a1c243Jonathan Adams	size = ulwp->ul_stksiz;
9824a1c243Jonathan Adams
9834a1c243Jonathan Adams	/*
9844a1c243Jonathan Adams	 * The main stack ends up being a little weird, especially if
9854a1c243Jonathan Adams	 * the stack ulimit is unlimited.  This tries to take that into
9864a1c243Jonathan Adams	 * account.
9874a1c243Jonathan Adams	 */
9884a1c243Jonathan Adams	if (size > top)
9894a1c243Jonathan Adams		size = top;
9904a1c243Jonathan Adams	if (top > MIN_STACK_ADDR && top - size < MIN_STACK_ADDR)
9914a1c243Jonathan Adams		size = top - MIN_STACK_ADDR;
9924a1c243Jonathan Adams
9934a1c243Jonathan Adams	base = top - size;
9944a1c243Jonathan Adams
9954a1c243Jonathan Adams	while (mdb_whatis_match(w, base, size, &cur))
9964a1c243Jonathan Adams		mdb_whatis_report_address(w, cur, "in [ stack tid=%#r ]\n", id);
9974a1c243Jonathan Adams
9984a1c243Jonathan Adams	if (ulwp->ul_ustack.ss_flags & SS_ONSTACK) {
9994a1c243Jonathan Adams		base = (uintptr_t)ulwp->ul_ustack.ss_sp;
10004a1c243Jonathan Adams		size = ulwp->ul_ustack.ss_size;
10014a1c243Jonathan Adams
10024a1c243Jonathan Adams		while (mdb_whatis_match(w, base, size, &cur))
10034a1c243Jonathan Adams			mdb_whatis_report_address(w, cur,
10044a1c243Jonathan Adams			    "in [ altstack tid=%#r ]\n", id);
10054a1c243Jonathan Adams	}
10064a1c243Jonathan Adams
10074a1c243Jonathan Adams	return (WHATIS_WALKRET(w));
10084a1c243Jonathan Adams}
10094a1c243Jonathan Adams
10104a1c243Jonathan Adams/*ARGSUSED*/
10114a1c243Jonathan Adamsstatic int
10124a1c243Jonathan Adamswhatis_run_ulwps(mdb_whatis_t *w, void *arg)
10134a1c243Jonathan Adams{
10144a1c243Jonathan Adams	if (mdb_walk("ulwps", (mdb_walk_cb_t)whatis_walk_ulwp, w) == -1) {
10154a1c243Jonathan Adams		mdb_warn("couldn't find ulwps walker");
10164a1c243Jonathan Adams		return (1);
10174a1c243Jonathan Adams	}
10184a1c243Jonathan Adams	return (0);
10194a1c243Jonathan Adams}
10204a1c243Jonathan Adams
10217c478bdstevel@tonic-gate/*
10227c478bdstevel@tonic-gate * =======================================================
10237c478bdstevel@tonic-gate * End of thread (previously libthread) interfaces.
10247c478bdstevel@tonic-gate * ==================== threads ==========================
10257c478bdstevel@tonic-gate */
10267c478bdstevel@tonic-gate
1027c9a6ea2Bryan Cantrillint
1028c9a6ea2Bryan Cantrillstacks_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1029c9a6ea2Bryan Cantrill{
1030c9a6ea2Bryan Cantrill	int rval = stacks(addr, flags, argc, argv);
1031c9a6ea2Bryan Cantrill
1032c9a6ea2Bryan Cantrill	/*
1033c9a6ea2Bryan Cantrill	 * For the user-level variant of ::stacks, we don't bother caching
1034c9a6ea2Bryan Cantrill	 * state, as even a very large program is unlikely to compare to the
1035c9a6ea2Bryan Cantrill	 * kernel in terms of number of threads.  (And if you find yourself
1036c9a6ea2Bryan Cantrill	 * here in anger, frustrated about how long ::stacks is running on
1037c9a6ea2Bryan Cantrill	 * your galactically complicated zillion-thread program, hopefully
1038c9a6ea2Bryan Cantrill	 * you will find some solace in the irony.  Okay, probably not...)
1039c9a6ea2Bryan Cantrill	 */
1040c9a6ea2Bryan Cantrill	stacks_cleanup(B_TRUE);
1041c9a6ea2Bryan Cantrill	return (rval);
1042c9a6ea2Bryan Cantrill}
1043c9a6ea2Bryan Cantrill
1044c9a6ea2Bryan Cantrilltypedef struct tid2ulwp_walk {
1045c9a6ea2Bryan Cantrill	lwpid_t t2u_tid;
1046c9a6ea2Bryan Cantrill	uintptr_t t2u_lwp;
1047c9a6ea2Bryan Cantrill	boolean_t t2u_found;
1048c9a6ea2Bryan Cantrill} tid2ulwp_walk_t;
1049c9a6ea2Bryan Cantrill
1050c9a6ea2Bryan Cantrill/*ARGSUSED*/
1051c9a6ea2Bryan Cantrillstatic int
1052c9a6ea2Bryan Cantrilltid2ulwp_walk(uintptr_t addr, ulwp_t *ulwp, tid2ulwp_walk_t *t2u)
1053c9a6ea2Bryan Cantrill{
1054c9a6ea2Bryan Cantrill	if (ulwp->ul_lwpid == t2u->t2u_tid) {
1055c9a6ea2Bryan Cantrill		t2u->t2u_lwp = addr;
1056c9a6ea2Bryan Cantrill		t2u->t2u_found = B_TRUE;
1057c9a6ea2Bryan Cantrill		return (WALK_DONE);
1058c9a6ea2Bryan Cantrill	}
1059c9a6ea2Bryan Cantrill
1060c9a6ea2Bryan Cantrill	return (WALK_NEXT);
1061c9a6ea2Bryan Cantrill}
1062c9a6ea2Bryan Cantrill
1063c9a6ea2Bryan Cantrillstatic int
106428e4da2Matthew Ahrenstid2ulwp_impl(uintptr_t tid_addr, uintptr_t *ulwp_addrp)
1065c9a6ea2Bryan Cantrill{
1066c9a6ea2Bryan Cantrill	tid2ulwp_walk_t t2u;
1067c9a6ea2Bryan Cantrill
1068c9a6ea2Bryan Cantrill	bzero(&t2u, sizeof (t2u));
106928e4da2Matthew Ahrens	t2u.t2u_tid = (lwpid_t)tid_addr;
1070c9a6ea2Bryan Cantrill
1071c9a6ea2Bryan Cantrill	if (mdb_walk("ulwp", (mdb_walk_cb_t)tid2ulwp_walk, &t2u) != 0) {
1072c9a6ea2Bryan Cantrill		mdb_warn("can't walk 'ulwp'");
1073c9a6ea2Bryan Cantrill		return (DCMD_ERR);
1074c9a6ea2Bryan Cantrill	}
1075c9a6ea2Bryan Cantrill
1076c9a6ea2Bryan Cantrill	if (!t2u.t2u_found) {
1077c9a6ea2Bryan Cantrill		mdb_warn("thread ID %d not found", t2u.t2u_tid);
1078c9a6ea2Bryan Cantrill		return (DCMD_ERR);
1079c9a6ea2Bryan Cantrill	}
108028e4da2Matthew Ahrens	*ulwp_addrp = t2u.t2u_lwp;
108128e4da2Matthew Ahrens	return (DCMD_OK);
108228e4da2Matthew Ahrens}
1083c9a6ea2Bryan Cantrill
108428e4da2Matthew Ahrens/*ARGSUSED*/
108528e4da2Matthew Ahrensstatic int
108628e4da2Matthew Ahrenstid2ulwp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
108728e4da2Matthew Ahrens{
108828e4da2Matthew Ahrens	uintptr_t ulwp_addr;
108928e4da2Matthew Ahrens	int error;
109028e4da2Matthew Ahrens
109128e4da2Matthew Ahrens	if (argc != 0)
109228e4da2Matthew Ahrens		return (DCMD_USAGE);
109328e4da2Matthew Ahrens
109428e4da2Matthew Ahrens	error = tid2ulwp_impl(addr, &ulwp_addr);
109528e4da2Matthew Ahrens	if (error == DCMD_OK)
109628e4da2Matthew Ahrens		mdb_printf("%p\n", ulwp_addr);
109728e4da2Matthew Ahrens	return (error);
109828e4da2Matthew Ahrens}
109928e4da2Matthew Ahrens
11000718894Jason King/*
11010718894Jason King * This is used by both d_tsd and d_errno, and contains the sum of all
11020718894Jason King * members used by both commands.
11030718894Jason King */
110428e4da2Matthew Ahrenstypedef struct mdb_libc_ulwp {
110528e4da2Matthew Ahrens	void *ul_ftsd[TSD_NFAST];
110628e4da2Matthew Ahrens	tsd_t *ul_stsd;
11070718894Jason King	int *ul_errnop;
110828e4da2Matthew Ahrens} mdb_libc_ulwp_t;
110928e4da2Matthew Ahrens
111028e4da2Matthew Ahrens/*
111128e4da2Matthew Ahrens * Map from thread pointer to tsd for given key
111228e4da2Matthew Ahrens */
111328e4da2Matthew Ahrensstatic int
111428e4da2Matthew Ahrensd_tsd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
111528e4da2Matthew Ahrens{
111628e4da2Matthew Ahrens	mdb_libc_ulwp_t u;
111728e4da2Matthew Ahrens	uintptr_t ulwp_addr;
1118892ad16Toomas Soome	uintptr_t key = 0;
111928e4da2Matthew Ahrens	void *element = NULL;
112028e4da2Matthew Ahrens
112128e4da2Matthew Ahrens	if (mdb_getopts(argc, argv, 'k', MDB_OPT_UINTPTR, &key, NULL) != argc)
112228e4da2Matthew Ahrens		return (DCMD_USAGE);
112328e4da2Matthew Ahrens
1124892ad16Toomas Soome	if (!(flags & DCMD_ADDRSPEC) || key == 0)
112528e4da2Matthew Ahrens		return (DCMD_USAGE);
112628e4da2Matthew Ahrens
112728e4da2Matthew Ahrens	if (tid2ulwp_impl(addr, &ulwp_addr) != DCMD_OK)
112828e4da2Matthew Ahrens		return (DCMD_ERR);
112928e4da2Matthew Ahrens
113028e4da2Matthew Ahrens	if (mdb_ctf_vread(&u, "ulwp_t", "mdb_libc_ulwp_t", ulwp_addr, 0) == -1)
113128e4da2Matthew Ahrens		return (DCMD_ERR);
113228e4da2Matthew Ahrens
113328e4da2Matthew Ahrens	if (key < TSD_NFAST) {
113428e4da2Matthew Ahrens		element = u.ul_ftsd[key];
113528e4da2Matthew Ahrens	} else if (u.ul_stsd != NULL) {
113628e4da2Matthew Ahrens		uint_t nalloc;
113728e4da2Matthew Ahrens		/* tsd_t is a union, so we can't use ctf_vread() on it. */
113828e4da2Matthew Ahrens		if (mdb_vread(&nalloc, sizeof (nalloc),
113928e4da2Matthew Ahrens		    (uintptr_t)&u.ul_stsd->tsd_nalloc) == -1) {
114028e4da2Matthew Ahrens			mdb_warn("failed to read tsd_t at %p", u.ul_stsd);
114128e4da2Matthew Ahrens			return (DCMD_ERR);
114228e4da2Matthew Ahrens		}
114328e4da2Matthew Ahrens		if (key < nalloc) {
114428e4da2Matthew Ahrens			if (mdb_vread(&element, sizeof (element),
114528e4da2Matthew Ahrens			    (uintptr_t)&u.ul_stsd->tsd_data[key]) == -1) {
114628e4da2Matthew Ahrens				mdb_warn("failed to read tsd_t at %p",
114728e4da2Matthew Ahrens				    u.ul_stsd);
114828e4da2Matthew Ahrens				return (DCMD_ERR);
114928e4da2Matthew Ahrens			}
115028e4da2Matthew Ahrens		}
115128e4da2Matthew Ahrens	}
115228e4da2Matthew Ahrens
115328e4da2Matthew Ahrens	if (element == NULL && (flags & DCMD_PIPE))
115428e4da2Matthew Ahrens		return (DCMD_OK);
1155c9a6ea2Bryan Cantrill
115628e4da2Matthew Ahrens	mdb_printf("%p\n", element);
1157c9a6ea2Bryan Cantrill	return (DCMD_OK);
1158c9a6ea2Bryan Cantrill}
1159c9a6ea2Bryan Cantrill
1160542a7b7Carlos Neira/*
1161542a7b7Carlos Neira * Print percent from 16-bit binary fraction [0 .. 1]
1162542a7b7Carlos Neira * Round up .01 to .1 to indicate some small percentage (the 0x7000 below).
1163542a7b7Carlos Neira *
1164542a7b7Carlos Neira * Note: This routine was copied from elfdump/common/corenote.c	and modified.
1165542a7b7Carlos Neira *
1166542a7b7Carlos Neira */
1167542a7b7Carlos Neirastatic uint_t
1168542a7b7Carlos Neirapct_value(ushort_t pct)
1169542a7b7Carlos Neira{
1170542a7b7Carlos Neira	uint_t value = pct;
1171542a7b7Carlos Neira
1172542a7b7Carlos Neira	value = ((value * 1000) + 0x7000) >> 15;	/* [0 .. 1000] */
1173542a7b7Carlos Neira	if (value >= 1000)
1174542a7b7Carlos Neira		value = 999;
1175542a7b7Carlos Neira
1176542a7b7Carlos Neira	return (value);
1177542a7b7Carlos Neira}
1178542a7b7Carlos Neira
1179542a7b7Carlos Neirastatic void
1180542a7b7Carlos Neirapsinfo_raw(psinfo_t psinfo)
1181542a7b7Carlos Neira{
1182542a7b7Carlos Neira	const int minspaces = 2;
1183542a7b7Carlos Neira	const int spbcols = 20;
1184542a7b7Carlos Neira	char sysname[SYS2STR_MAX];
1185542a7b7Carlos Neira	uint_t cpu, mem;
1186542a7b7Carlos Neira	char buff[32];
1187542a7b7Carlos Neira	int bufflen;
1188542a7b7Carlos Neira
1189542a7b7Carlos Neira	mdb_printf("[ NT_PRPSINFO ]\n");
1190542a7b7Carlos Neira
1191542a7b7Carlos Neira	mdb_printf("\tpr_state:   %d\t\t\tpr_sname:   %c\n",
1192542a7b7Carlos Neira	    psinfo.pr_lwp.pr_state, psinfo.pr_lwp.pr_sname);
1193542a7b7Carlos Neira
1194542a7b7Carlos Neira	mdb_printf("\tpr_zomb:    %d\t\t\tpr_nice:    %d\n",
1195542a7b7Carlos Neira	    psinfo.pr_nzomb, psinfo.pr_lwp.pr_nice);
1196542a7b7Carlos Neira
1197542a7b7Carlos Neira	mdb_printf("\tpr_uid:     %u\t\t\tpr_gid:     %u\n",
1198542a7b7Carlos Neira	    psinfo.pr_uid, psinfo.pr_gid);
1199542a7b7Carlos Neira
1200542a7b7Carlos Neira	mdb_snprintf(buff, sizeof (buff),
1201542a7b7Carlos Neira	    "%d", psinfo.pr_pid);
1202542a7b7Carlos Neira
1203542a7b7Carlos Neira	bufflen = strlen(buff);
1204542a7b7Carlos Neira	mdb_printf("\tpr_pid:     %s%*spr_ppid:    %d\n",
1205542a7b7Carlos Neira	    buff, strlen(buff) > spbcols ? minspaces : (spbcols - bufflen), " ",
1206542a7b7Carlos Neira	    psinfo.pr_ppid);
1207542a7b7Carlos Neira
1208542a7b7Carlos Neira	mdb_printf("\tpr_pgid:    %u\t\t\tpr_sid:     %d\n",
1209542a7b7Carlos Neira	    psinfo.pr_gid, psinfo.pr_sid);
1210542a7b7Carlos Neira
1211542a7b7Carlos Neira	mdb_snprintf(buff, sizeof (buff),
1212542a7b7Carlos Neira	    "0x%lx", (ulong_t)psinfo.pr_addr);
1213542a7b7Carlos Neira
1214542a7b7Carlos Neira	bufflen = strlen(buff);
1215542a7b7Carlos Neira
1216542a7b7Carlos Neira	mdb_printf("\tpr_addr:    %s%*spr_size:    %#x\n",
1217542a7b7Carlos Neira	    buff, strlen(buff) > spbcols ? minspaces : (spbcols - bufflen), " ",
1218542a7b7Carlos Neira	    (ulong_t)psinfo.pr_size);
1219542a7b7Carlos Neira
1220542a7b7Carlos Neira	mdb_printf("\tpr_rssize:  %#lx\t\tpr_wchan:   %#lx\n",
1221542a7b7Carlos Neira	    (ulong_t)psinfo.pr_rssize, (ulong_t)psinfo.pr_lwp.pr_wchan);
1222542a7b7Carlos Neira
1223542a7b7Carlos Neira	mdb_printf("\tpr_start:\n\t    tv_sec: %ld\t\ttv_nsec:    %ld\n",
1224542a7b7Carlos Neira	    psinfo.pr_start.tv_sec, psinfo.pr_start.tv_nsec);
1225542a7b7Carlos Neira
1226542a7b7Carlos Neira	mdb_printf("\tpr_time:\n\t    tv_sec: %ld\t\t\ttv_nsec:    %ld\n",
1227542a7b7Carlos Neira	    psinfo.pr_time.tv_sec, psinfo.pr_time.tv_nsec);
1228542a7b7Carlos Neira
1229542a7b7Carlos Neira	mdb_printf("\tpr_pri:     %d\t\t\tpr_oldpri:  %d\n",
1230542a7b7Carlos Neira	    psinfo.pr_lwp.pr_pri, psinfo.pr_lwp.pr_oldpri);
1231542a7b7Carlos Neira
1232542a7b7Carlos Neira	mdb_printf("\tpr_cpu:     %d\n", psinfo.pr_lwp.pr_cpu);
1233542a7b7Carlos Neira
1234542a7b7Carlos Neira	mdb_printf("\tpr_clname:  %s\n", psinfo.pr_lwp.pr_clname);
1235542a7b7Carlos Neira
1236542a7b7Carlos Neira	mdb_printf("\tpr_fname:   %s\n", psinfo.pr_fname);
1237542a7b7Carlos Neira
1238542a7b7Carlos Neira	mdb_printf("\tpr_psargs:  %s\n", psinfo.pr_psargs);
1239542a7b7Carlos Neira
1240542a7b7Carlos Neira
1241542a7b7Carlos Neira	mdb_printf("\tpr_syscall: [ %s ]\n",
1242542a7b7Carlos Neira	    proc_sysname(psinfo.pr_lwp.pr_syscall, sysname,
1243542a7b7Carlos Neira	    sizeof (sysname)));
1244542a7b7Carlos Neira
1245542a7b7Carlos Neira	mdb_printf("\tpr_ctime:\n\t    tv_sec: %ld\t\t\ttv_nsec:    %ld\n",
1246542a7b7Carlos Neira	    psinfo.pr_ctime.tv_sec, psinfo.pr_ctime.tv_nsec);
1247542a7b7Carlos Neira
1248542a7b7Carlos Neira	mdb_printf("\tpr_argc:    %d\t\t\tpr_argv:    0x%lx\n",
1249542a7b7Carlos Neira	    psinfo.pr_argc, (ulong_t)psinfo.pr_argv);
1250542a7b7Carlos Neira
1251542a7b7Carlos Neira	mdb_snprintf(buff, sizeof (buff), "0x%lx", (ulong_t)psinfo.pr_envp);
1252542a7b7Carlos Neira
1253542a7b7Carlos Neira	bufflen = strlen(buff);
1254542a7b7Carlos Neira
1255542a7b7Carlos Neira	mdb_printf("\tpr_envp:    %s%*spr_wstat:   %d\n",
1256542a7b7Carlos Neira	    buff, strlen(buff) > spbcols ? minspaces : (spbcols - bufflen), " ",
1257542a7b7Carlos Neira	    psinfo.pr_wstat);
1258542a7b7Carlos Neira
1259542a7b7Carlos Neira	cpu = pct_value(psinfo.pr_pctcpu);
1260542a7b7Carlos Neira	mem = pct_value(psinfo.pr_pctmem);
1261542a7b7Carlos Neira
1262542a7b7Carlos Neira	mdb_printf("\tpr_pctcpu:  %u.%u%%\t\tpr_pctmem:  %u.%u%%\n",
1263542a7b7Carlos Neira	    cpu / 10, cpu % 10, mem / 10, mem % 10);
1264542a7b7Carlos Neira
1265542a7b7Carlos Neira	mdb_printf("\tpr_euid:    %u\t\t\tpr_egid:    %u\n",
1266542a7b7Carlos Neira	    psinfo.pr_euid, psinfo.pr_egid);
1267542a7b7Carlos Neira
1268542a7b7Carlos Neira	mdb_printf("\tpr_dmodel:  [%s]\n",
1269542a7b7Carlos Neira	    proc_dmodelname(psinfo.pr_dmodel, buff, sizeof (buff)));
1270542a7b7Carlos Neira}
1271542a7b7Carlos Neira
1272542a7b7Carlos Neirastatic void
1273542a7b7Carlos Neirapsinfo_sum(psinfo_t psinfo)
1274542a7b7Carlos Neira{
1275542a7b7Carlos Neira	const int minspaces = 2;
1276542a7b7Carlos Neira	const int spbcols = 23;
1277542a7b7Carlos Neira	char buff[64];
1278542a7b7Carlos Neira	int bufflen;
1279542a7b7Carlos Neira	int ms;
1280542a7b7Carlos Neira
1281542a7b7Carlos Neira	mdb_printf("PID:    %6d  (process id)\t\t"
1282542a7b7Carlos Neira	    "UID:     %4u  (real user id)\n",
1283542a7b7Carlos Neira	    psinfo.pr_pid, psinfo.pr_uid);
1284542a7b7Carlos Neira
1285542a7b7Carlos Neira	mdb_printf("PPID:   %6d  (parent process id)\tEUID:    %4d"
1286542a7b7Carlos Neira	    "  (effective user id)\n", psinfo.pr_ppid, psinfo.pr_euid);
1287542a7b7Carlos Neira
1288542a7b7Carlos Neira	mdb_printf("PGID:   %6d  (process group id)\tGID:     %4u"
1289542a7b7Carlos Neira	    "  (real group id)\n", psinfo.pr_pgid, psinfo.pr_gid);
1290542a7b7Carlos Neira
1291542a7b7Carlos Neira	mdb_printf("SID:    %6d  (session id)\t\tEGID:    %4u"
1292542a7b7Carlos Neira	    "  (effective group id)\n",
1293542a7b7Carlos Neira	    psinfo.pr_sid, psinfo.pr_egid);
1294542a7b7Carlos Neira
1295542a7b7Carlos Neira	mdb_printf("ZONEID: %6d\t\t\t\tCONTRACT:%4d\n",
1296542a7b7Carlos Neira	    psinfo.pr_zoneid, psinfo.pr_contract);
1297542a7b7Carlos Neira
1298542a7b7Carlos Neira	mdb_printf("PROJECT:%6d \t\t\t\tTASK:    %4d\n\n",
1299542a7b7Carlos Neira	    psinfo.pr_projid, psinfo.pr_taskid);
1300542a7b7Carlos Neira
1301542a7b7Carlos Neira	mdb_printf("START: %Y   (wall timestamp when the process started)\n",
1302542a7b7Carlos Neira	    psinfo.pr_start);
1303542a7b7Carlos Neira
1304542a7b7Carlos Neira	ms = NSEC2MSEC(psinfo.pr_time.tv_nsec);
1305542a7b7Carlos Neira
1306542a7b7Carlos Neira	mdb_snprintf(buff, sizeof (buff), "%ld.%d seconds",
1307542a7b7Carlos Neira	    psinfo.pr_time.tv_sec, ms);
1308542a7b7Carlos Neira
1309542a7b7Carlos Neira	bufflen = strlen(buff);
1310542a7b7Carlos Neira
1311542a7b7Carlos Neira	mdb_printf("TIME:  %s%*s"
1312542a7b7Carlos Neira	    "(CPU time used by this process)\n",
1313542a7b7Carlos Neira	    buff, bufflen > spbcols ? minspaces : (spbcols - bufflen), " ");
1314542a7b7Carlos Neira
1315542a7b7Carlos Neira	ms = NSEC2MSEC(psinfo.pr_ctime.tv_nsec);
1316542a7b7Carlos Neira
1317542a7b7Carlos Neira	mdb_snprintf(buff, sizeof (buff), "%ld.%d seconds",
1318542a7b7Carlos Neira	    psinfo.pr_ctime.tv_sec, ms);
1319542a7b7Carlos Neira
1320542a7b7Carlos Neira	mdb_printf("CTIME: %s%*s"
1321542a7b7Carlos Neira	    "(CPU time used by child processes)\n",
1322542a7b7Carlos Neira	    buff, bufflen > spbcols ? minspaces : (spbcols - bufflen), " ");
1323542a7b7Carlos Neira
1324542a7b7Carlos Neira	mdb_snprintf(buff, sizeof (buff), "%s", psinfo.pr_fname);
1325542a7b7Carlos Neira	bufflen = strlen(buff);
1326542a7b7Carlos Neira
1327542a7b7Carlos Neira	mdb_printf("FNAME: %s%*s(name of the program executed)\n",
1328542a7b7Carlos Neira	    buff, bufflen > spbcols ? minspaces : (spbcols - bufflen), " ");
1329542a7b7Carlos Neira
1330542a7b7Carlos Neira	mdb_printf("PSARGS: \"%s\"\n", psinfo.pr_psargs);
1331542a7b7Carlos Neira}
1332542a7b7Carlos Neira
1333542a7b7Carlos Neiravoid
1334542a7b7Carlos Neirad_psinfo_dcmd_help(void)
1335542a7b7Carlos Neira{
1336542a7b7Carlos Neira	mdb_printf(
1337542a7b7Carlos Neira	    "Prints relevant fields from psinfo_t data and\n"
1338542a7b7Carlos Neira	    "most fields from NT_PRPSINFO note section\n\n"
1339542a7b7Carlos Neira	    "Usage:  ::psinfo [-v]\n"
1340542a7b7Carlos Neira	    "Options:\n"
1341542a7b7Carlos Neira	    "   -v   verbose output\n");
1342542a7b7Carlos Neira}
1343542a7b7Carlos Neira
1344542a7b7Carlos Neirastatic int
1345542a7b7Carlos Neirad_psinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1346542a7b7Carlos Neira{
1347542a7b7Carlos Neira	psinfo_t psinfo;
1348542a7b7Carlos Neira	uint_t opt_v = FALSE;
1349542a7b7Carlos Neira	ssize_t nbytes;
1350542a7b7Carlos Neira
1351542a7b7Carlos Neira	if (mdb_getopts(argc, argv, 'v',
1352542a7b7Carlos Neira	    MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
1353542a7b7Carlos Neira		return (DCMD_USAGE);
1354542a7b7Carlos Neira
1355542a7b7Carlos Neira	nbytes = mdb_get_xdata("psinfo", NULL, 0);
1356542a7b7Carlos Neira
1357542a7b7Carlos Neira	if (nbytes <= 0) {
1358542a7b7Carlos Neira		mdb_warn("information not available for analysis");
1359542a7b7Carlos Neira		return (DCMD_ERR);
1360542a7b7Carlos Neira	}
1361542a7b7Carlos Neira
1362542a7b7Carlos Neira	if (mdb_get_xdata("psinfo", &psinfo, nbytes) != nbytes) {
1363542a7b7Carlos Neira		mdb_warn("failed to read psinfo information");
1364542a7b7Carlos Neira		return (DCMD_ERR);
1365