11a7c1b7mws/*
21a7c1b7mws * CDDL HEADER START
31a7c1b7mws *
41a7c1b7mws * The contents of this file are subject to the terms of the
5ac44896ahl * Common Development and Distribution License (the "License").
6ac44896ahl * You may not use this file except in compliance with the License.
71a7c1b7mws *
81a7c1b7mws * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91a7c1b7mws * or http://www.opensolaris.org/os/licensing.
101a7c1b7mws * See the License for the specific language governing permissions
111a7c1b7mws * and limitations under the License.
121a7c1b7mws *
131a7c1b7mws * When distributing Covered Code, include this CDDL HEADER in each
141a7c1b7mws * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151a7c1b7mws * If applicable, add the following below this CDDL HEADER, with the
161a7c1b7mws * fields enclosed by brackets "[]" replaced with your own identifying
171a7c1b7mws * information: Portions Copyright [yyyy] [name of copyright owner]
181a7c1b7mws *
191a7c1b7mws * CDDL HEADER END
201a7c1b7mws */
21ac44896ahl
221a7c1b7mws/*
23ac44896ahl * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
241a7c1b7mws * Use is subject to license terms.
251a7c1b7mws */
261a7c1b7mws
271a7c1b7mws#pragma ident	"%Z%%M%	%I%	%E% SMI"
281a7c1b7mws
291a7c1b7mws#include <mdb/mdb_modapi.h>
301a7c1b7mws#include <dtrace.h>
311a7c1b7mws
321a7c1b7mwsextern int dof_sec(uintptr_t, uint_t, int, const mdb_arg_t *);
331a7c1b7mwsextern const char *dof_sec_name(uint32_t);
341a7c1b7mws
351a7c1b7mwsextern const mdb_walker_t kernel_walkers[];
361a7c1b7mwsextern const mdb_dcmd_t kernel_dcmds[];
371a7c1b7mws
381a7c1b7mws/*ARGSUSED*/
391a7c1b7mwsstatic void
401a7c1b7mwsdis_log(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
411a7c1b7mws{
421a7c1b7mws	mdb_printf("%-4s %%r%u, %%r%u, %%r%u", name,
431a7c1b7mws	    DIF_INSTR_R1(instr), DIF_INSTR_R2(instr), DIF_INSTR_RD(instr));
441a7c1b7mws}
451a7c1b7mws
461a7c1b7mws/*ARGSUSED*/
471a7c1b7mwsstatic void
481a7c1b7mwsdis_branch(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
491a7c1b7mws{
501a7c1b7mws	mdb_printf("%-4s %u", name, DIF_INSTR_LABEL(instr));
511a7c1b7mws}
521a7c1b7mws
531a7c1b7mws/*ARGSUSED*/
541a7c1b7mwsstatic void
551a7c1b7mwsdis_load(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
561a7c1b7mws{
571a7c1b7mws	mdb_printf("%-4s [%%r%u], %%r%u", name,
581a7c1b7mws	    DIF_INSTR_R1(instr), DIF_INSTR_RD(instr));
591a7c1b7mws}
601a7c1b7mws
611a7c1b7mws/*ARGSUSED*/
621a7c1b7mwsstatic void
631a7c1b7mwsdis_store(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
641a7c1b7mws{
651a7c1b7mws	mdb_printf("%-4s %%r%u, [%%r%u]", name,
661a7c1b7mws	    DIF_INSTR_R1(instr), DIF_INSTR_RD(instr));
671a7c1b7mws}
681a7c1b7mws
691a7c1b7mws/*ARGSUSED*/
701a7c1b7mwsstatic void
711a7c1b7mwsdis_str(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
721a7c1b7mws{
731a7c1b7mws	mdb_printf("%s", name);
741a7c1b7mws}
751a7c1b7mws
761a7c1b7mws/*ARGSUSED*/
771a7c1b7mwsstatic void
781a7c1b7mwsdis_r1rd(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
791a7c1b7mws{
801a7c1b7mws	mdb_printf("%-4s %%r%u, %%r%u", name,
811a7c1b7mws	    DIF_INSTR_R1(instr), DIF_INSTR_RD(instr));
821a7c1b7mws}
831a7c1b7mws
841a7c1b7mws/*ARGSUSED*/
851a7c1b7mwsstatic void
861a7c1b7mwsdis_cmp(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
871a7c1b7mws{
881a7c1b7mws	mdb_printf("%-4s %%r%u, %%r%u", name,
891a7c1b7mws	    DIF_INSTR_R1(instr), DIF_INSTR_R2(instr));
901a7c1b7mws}
911a7c1b7mws
921a7c1b7mws/*ARGSUSED*/
931a7c1b7mwsstatic void
941a7c1b7mwsdis_tst(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
951a7c1b7mws{
961a7c1b7mws	mdb_printf("%-4s %%r%u", name, DIF_INSTR_R1(instr));
971a7c1b7mws}
981a7c1b7mws
991a7c1b7mwsstatic const char *
1001a7c1b7mwsdis_varname(const dtrace_difo_t *dp, uint_t id, uint_t scope)
1011a7c1b7mws{
1021a7c1b7mws	dtrace_difv_t *dvp;
1031a7c1b7mws	size_t varsize;
1041a7c1b7mws	caddr_t addr = NULL, str;
1051a7c1b7mws	uint_t i;
1061a7c1b7mws
1071a7c1b7mws	if (dp == NULL)
1081a7c1b7mws		return (NULL);
1091a7c1b7mws
1101a7c1b7mws	varsize = sizeof (dtrace_difv_t) * dp->dtdo_varlen;
1111a7c1b7mws	dvp = mdb_alloc(varsize, UM_SLEEP);
1121a7c1b7mws
1131a7c1b7mws	if (mdb_vread(dvp, varsize, (uintptr_t)dp->dtdo_vartab) == -1) {
1141a7c1b7mws		mdb_free(dvp, varsize);
1151a7c1b7mws		return ("<unreadable>");
1161a7c1b7mws	}
1171a7c1b7mws
1181a7c1b7mws	for (i = 0; i < dp->dtdo_varlen; i++) {
1191a7c1b7mws		if (dvp[i].dtdv_id == id && dvp[i].dtdv_scope == scope) {
1201a7c1b7mws			if (dvp[i].dtdv_name < dp->dtdo_strlen)
1211a7c1b7mws				addr = dp->dtdo_strtab + dvp[i].dtdv_name;
1221a7c1b7mws			break;
1231a7c1b7mws		}
1241a7c1b7mws	}
1251a7c1b7mws
1261a7c1b7mws	mdb_free(dvp, varsize);
1271a7c1b7mws
1281a7c1b7mws	if (addr == NULL)
1291a7c1b7mws		return (NULL);
1301a7c1b7mws
1311a7c1b7mws	str = mdb_zalloc(dp->dtdo_strlen + 1, UM_SLEEP | UM_GC);
1321a7c1b7mws
1331a7c1b7mws	for (i = 0; i == 0 || str[i - 1] != '\0'; i++, addr++) {
1341a7c1b7mws		if (mdb_vread(&str[i], sizeof (char), (uintptr_t)addr) == -1)
1351a7c1b7mws			return ("<unreadable>");
1361a7c1b7mws	}
1371a7c1b7mws
1381a7c1b7mws	return (str);
1391a7c1b7mws}
1401a7c1b7mws
1411a7c1b7mwsstatic uint_t
1421a7c1b7mwsdis_scope(const char *name)
1431a7c1b7mws{
1441a7c1b7mws	switch (name[2]) {
1451a7c1b7mws	case 'l': return (DIFV_SCOPE_LOCAL);
1461a7c1b7mws	case 't': return (DIFV_SCOPE_THREAD);
1471a7c1b7mws	case 'g': return (DIFV_SCOPE_GLOBAL);
1481a7c1b7mws	default: return (-1u);
1491a7c1b7mws	}
1501a7c1b7mws}
1511a7c1b7mws
1521a7c1b7mwsstatic void
1531a7c1b7mwsdis_lda(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
1541a7c1b7mws{
1551a7c1b7mws	uint_t var = DIF_INSTR_R1(instr);
1561a7c1b7mws	const char *vname;
1571a7c1b7mws
1581a7c1b7mws	mdb_printf("%-4s DIF_VAR(%x), %%r%u, %%r%u", name,
1591a7c1b7mws	    var, DIF_INSTR_R2(instr), DIF_INSTR_RD(instr));
1601a7c1b7mws
1611a7c1b7mws	if ((vname = dis_varname(dp, var, dis_scope(name))) != NULL)
1621a7c1b7mws		mdb_printf("\t\t! %s", vname);
1631a7c1b7mws}
1641a7c1b7mws
1651a7c1b7mwsstatic void
1661a7c1b7mwsdis_ldv(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
1671a7c1b7mws{
1681a7c1b7mws	uint_t var = DIF_INSTR_VAR(instr);
1691a7c1b7mws	const char *vname;
1701a7c1b7mws
1711a7c1b7mws	mdb_printf("%-4s DIF_VAR(%x), %%r%u", name, var, DIF_INSTR_RD(instr));
1721a7c1b7mws
1731a7c1b7mws	if ((vname = dis_varname(dp, var, dis_scope(name))) != NULL)
1741a7c1b7mws		mdb_printf("\t\t! %s", vname);
1751a7c1b7mws}
1761a7c1b7mws
1771a7c1b7mwsstatic void
1781a7c1b7mwsdis_stv(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
1791a7c1b7mws{
1801a7c1b7mws	uint_t var = DIF_INSTR_VAR(instr);
1811a7c1b7mws	const char *vname;
1821a7c1b7mws
1831a7c1b7mws	mdb_printf("%-4s %%r%u, DIF_VAR(%x)", name, DIF_INSTR_RS(instr), var);
1841a7c1b7mws
1851a7c1b7mws	if ((vname = dis_varname(dp, var, dis_scope(name))) != NULL)
1861a7c1b7mws		mdb_printf("\t\t! %s", vname);
1871a7c1b7mws}
1881a7c1b7mws
1891a7c1b7mwsstatic void
1901a7c1b7mwsdis_setx(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
1911a7c1b7mws{
1921a7c1b7mws	uint_t intptr = DIF_INSTR_INTEGER(instr);
1931a7c1b7mws
1941a7c1b7mws	mdb_printf("%-4s DIF_INTEGER[%u], %%r%u", name,
1951a7c1b7mws	    intptr, DIF_INSTR_RD(instr));
1961a7c1b7mws
1971a7c1b7mws	if (dp != NULL && intptr < dp->dtdo_intlen) {
1981a7c1b7mws		uint64_t *ip = mdb_alloc(dp->dtdo_intlen *
1991a7c1b7mws		    sizeof (uint64_t), UM_SLEEP | UM_GC);
2001a7c1b7mws
2011a7c1b7mws		if (mdb_vread(ip, dp->dtdo_intlen * sizeof (uint64_t),
2021a7c1b7mws		    (uintptr_t)dp->dtdo_inttab) == -1)
2031a7c1b7mws			mdb_warn("failed to read data at %p", dp->dtdo_inttab);
2041a7c1b7mws		else
2051a7c1b7mws			mdb_printf("\t\t! 0x%llx", ip[intptr]);
2061a7c1b7mws	}
2071a7c1b7mws}
2081a7c1b7mws
2091a7c1b7mwsstatic void
2101a7c1b7mwsdis_sets(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
2111a7c1b7mws{
2121a7c1b7mws	uint_t strptr = DIF_INSTR_STRING(instr);
2131a7c1b7mws
2141a7c1b7mws	mdb_printf("%-4s DIF_STRING[%u], %%r%u", name,
2151a7c1b7mws	    strptr, DIF_INSTR_RD(instr));
2161a7c1b7mws
2171a7c1b7mws	if (dp != NULL && strptr < dp->dtdo_strlen) {
2181a7c1b7mws		char *str = mdb_alloc(dp->dtdo_strlen, UM_SLEEP | UM_GC);
2191a7c1b7mws
2201a7c1b7mws		if (mdb_vread(str, dp->dtdo_strlen,
2211a7c1b7mws		    (uintptr_t)dp->dtdo_strtab) == -1)
2221a7c1b7mws			mdb_warn("failed to read data at %p", dp->dtdo_strtab);
2231a7c1b7mws		else
2241a7c1b7mws			mdb_printf("\t\t! \"%s\"", str + strptr);
2251a7c1b7mws	}
2261a7c1b7mws}
2271a7c1b7mws
2281a7c1b7mws/*ARGSUSED*/
2291a7c1b7mwsstatic void
2301a7c1b7mwsdis_ret(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
2311a7c1b7mws{
2321a7c1b7mws	mdb_printf("%-4s %%r%u", name, DIF_INSTR_RD(instr));
2331a7c1b7mws}
2341a7c1b7mws
2351a7c1b7mws/*ARGSUSED*/
2361a7c1b7mwsstatic void
2371a7c1b7mwsdis_call(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
2381a7c1b7mws{
2391a7c1b7mws	uint_t subr = DIF_INSTR_SUBR(instr);
2401a7c1b7mws
2411a7c1b7mws	mdb_printf("%-4s DIF_SUBR(%u), %%r%u\t\t! %s",
2421a7c1b7mws	    name, subr, DIF_INSTR_RD(instr), dtrace_subrstr(NULL, subr));
2431a7c1b7mws}
2441a7c1b7mws
2451a7c1b7mws/*ARGSUSED*/
2461a7c1b7mwsstatic void
2471a7c1b7mwsdis_pushts(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
2481a7c1b7mws{
2491a7c1b7mws	static const char *const tnames[] = { "TYPE_CTF", "TYPE_STRING" };
2501a7c1b7mws	uint_t type = DIF_INSTR_TYPE(instr);
2511a7c1b7mws
2521a7c1b7mws	mdb_printf("%-4s DIF_TYPE(%u), %%r%u, %%r%u",
2531a7c1b7mws	    name, type, DIF_INSTR_R2(instr), DIF_INSTR_RS(instr));
2541a7c1b7mws
2551a7c1b7mws	if (type < sizeof (tnames) / sizeof (tnames[0]))
256187eccfbmc		mdb_printf("\t\t! %s", tnames[type]);
2571a7c1b7mws}
2581a7c1b7mws
2591a7c1b7mws/*ARGSUSED*/
2601a7c1b7mwsstatic void
2611a7c1b7mwsdis_xlate(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
2621a7c1b7mws{
2631a7c1b7mws	mdb_printf("%-4s DIF_XLREF[%u], %%r%u", name,
2641a7c1b7mws	    DIF_INSTR_XLREF(instr), DIF_INSTR_RD(instr));
2651a7c1b7mws}
2661a7c1b7mws
2671a7c1b7mwsstatic char *
2681a7c1b7mwsdis_typestr(const dtrace_diftype_t *t, char *buf, size_t len)
2691a7c1b7mws{
2701a7c1b7mws	char kind[8];
2711a7c1b7mws
2721a7c1b7mws	switch (t->dtdt_kind) {
2731a7c1b7mws	case DIF_TYPE_CTF:
2741a7c1b7mws		(void) strcpy(kind, "D type");
2751a7c1b7mws		break;
2761a7c1b7mws	case DIF_TYPE_STRING:
2771a7c1b7mws		(void) strcpy(kind, "string");
2781a7c1b7mws		break;
2791a7c1b7mws	default:
2801a7c1b7mws		(void) mdb_snprintf(kind, sizeof (kind), "0x%x", t->dtdt_kind);
2811a7c1b7mws	}
2821a7c1b7mws
2831a7c1b7mws	if (t->dtdt_flags & DIF_TF_BYREF) {
2841a7c1b7mws		(void) mdb_snprintf(buf, len,
2851a7c1b7mws		    "%s by ref (size %lu)",
2861a7c1b7mws		    kind, (ulong_t)t->dtdt_size);
2871a7c1b7mws	} else {
2881a7c1b7mws		(void) mdb_snprintf(buf, len, "%s (size %lu)",
2891a7c1b7mws		    kind, (ulong_t)t->dtdt_size);
2901a7c1b7mws	}
2911a7c1b7mws
2921a7c1b7mws	return (buf);
2931a7c1b7mws}
2941a7c1b7mws
2951a7c1b7mwsstatic int
2961a7c1b7mwsdis(uintptr_t addr, dtrace_difo_t *dp)
2971a7c1b7mws{
2981a7c1b7mws	static const struct opent {
2991a7c1b7mws		const char *op_name;
3001a7c1b7mws		void (*op_func)(const dtrace_difo_t *,
3011a7c1b7mws		    const char *, dif_instr_t);
3021a7c1b7mws	} optab[] = {
3031a7c1b7mws		{ "(illegal opcode)", dis_str },
3041a7c1b7mws		{ "or", dis_log },		/* DIF_OP_OR */
3051a7c1b7mws		{ "xor", dis_log },		/* DIF_OP_XOR */
3061a7c1b7mws		{ "and", dis_log },		/* DIF_OP_AND */
3071a7c1b7mws		{ "sll", dis_log },		/* DIF_OP_SLL */
3081a7c1b7mws		{ "srl", dis_log },		/* DIF_OP_SRL */
3091a7c1b7mws		{ "sub", dis_log },		/* DIF_OP_SUB */
3101a7c1b7mws		{ "add", dis_log },		/* DIF_OP_ADD */
3111a7c1b7mws		{ "mul", dis_log },		/* DIF_OP_MUL */
3121a7c1b7mws		{ "sdiv", dis_log },		/* DIF_OP_SDIV */
3131a7c1b7mws		{ "udiv", dis_log },		/* DIF_OP_UDIV */
3141a7c1b7mws		{ "srem", dis_log },		/* DIF_OP_SREM */
3151a7c1b7mws		{ "urem", dis_log },		/* DIF_OP_UREM */
3161a7c1b7mws		{ "not", dis_r1rd },		/* DIF_OP_NOT */
3171a7c1b7mws		{ "mov", dis_r1rd },		/* DIF_OP_MOV */
3181a7c1b7mws		{ "cmp", dis_cmp },		/* DIF_OP_CMP */
3191a7c1b7mws		{ "tst", dis_tst },		/* DIF_OP_TST */
3201a7c1b7mws		{ "ba", dis_branch },		/* DIF_OP_BA */
3211a7c1b7mws		{ "be", dis_branch },		/* DIF_OP_BE */
3221a7c1b7mws		{ "bne", dis_branch },		/* DIF_OP_BNE */
3231a7c1b7mws		{ "bg", dis_branch },		/* DIF_OP_BG */
3241a7c1b7mws		{ "bgu", dis_branch },		/* DIF_OP_BGU */
3251a7c1b7mws		{ "bge", dis_branch },		/* DIF_OP_BGE */
3261a7c1b7mws		{ "bgeu", dis_branch },		/* DIF_OP_BGEU */
3271a7c1b7mws		{ "bl", dis_branch },		/* DIF_OP_BL */
3281a7c1b7mws		{ "blu", dis_branch },		/* DIF_OP_BLU */
3291a7c1b7mws		{ "ble", dis_branch },		/* DIF_OP_BLE */
3301a7c1b7mws		{ "bleu", dis_branch },		/* DIF_OP_BLEU */
3311a7c1b7mws		{ "ldsb", dis_load },		/* DIF_OP_LDSB */
3321a7c1b7mws		{ "ldsh", dis_load },		/* DIF_OP_LDSH */
3331a7c1b7mws		{ "ldsw", dis_load },		/* DIF_OP_LDSW */
3341a7c1b7mws		{ "ldub", dis_load },		/* DIF_OP_LDUB */
3351a7c1b7mws		{ "lduh", dis_load },		/* DIF_OP_LDUH */
3361a7c1b7mws		{ "lduw", dis_load },		/* DIF_OP_LDUW */
3371a7c1b7mws		{ "ldx", dis_load },		/* DIF_OP_LDX */
3381a7c1b7mws		{ "ret", dis_ret },		/* DIF_OP_RET */
3391a7c1b7mws		{ "nop", dis_str },		/* DIF_OP_NOP */
3401a7c1b7mws		{ "setx", dis_setx },		/* DIF_OP_SETX */
3411a7c1b7mws		{ "sets", dis_sets },		/* DIF_OP_SETS */
3421a7c1b7mws		{ "scmp", dis_cmp },		/* DIF_OP_SCMP */
3431a7c1b7mws		{ "ldga", dis_lda },		/* DIF_OP_LDGA */
3441a7c1b7mws		{ "ldgs", dis_ldv },		/* DIF_OP_LDGS */
3451a7c1b7mws		{ "stgs", dis_stv },		/* DIF_OP_STGS */
3461a7c1b7mws		{ "ldta", dis_lda },		/* DIF_OP_LDTA */
3471a7c1b7mws		{ "ldts", dis_ldv },		/* DIF_OP_LDTS */
3481a7c1b7mws		{ "stts", dis_stv },		/* DIF_OP_STTS */
3491a7c1b7mws		{ "sra", dis_log },		/* DIF_OP_SRA */
3501a7c1b7mws		{ "call", dis_call },		/* DIF_OP_CALL */
3511a7c1b7mws		{ "pushtr", dis_pushts },	/* DIF_OP_PUSHTR */
3521a7c1b7mws		{ "pushtv", dis_pushts },	/* DIF_OP_PUSHTV */
3531a7c1b7mws		{ "popts", dis_str },		/* DIF_OP_POPTS */
3541a7c1b7mws		{ "flushts", dis_str },		/* DIF_OP_FLUSHTS */
3551a7c1b7mws		{ "ldgaa", dis_ldv },		/* DIF_OP_LDGAA */
3561a7c1b7mws		{ "ldtaa", dis_ldv },		/* DIF_OP_LDTAA */
3571a7c1b7mws		{ "stgaa", dis_stv },		/* DIF_OP_STGAA */
3581a7c1b7mws		{ "sttaa", dis_stv },		/* DIF_OP_STTAA */
3591a7c1b7mws		{ "ldls", dis_ldv },		/* DIF_OP_LDLS */
3601a7c1b7mws		{ "stls", dis_stv },		/* DIF_OP_STLS */
3611a7c1b7mws		{ "allocs", dis_r1rd },		/* DIF_OP_ALLOCS */
3621a7c1b7mws		{ "copys", dis_log },		/* DIF_OP_COPYS */
3631a7c1b7mws		{ "stb", dis_store },		/* DIF_OP_STB */
3641a7c1b7mws		{ "sth", dis_store },		/* DIF_OP_STH */
3651a7c1b7mws		{ "stw", dis_store },		/* DIF_OP_STW */
3661a7c1b7mws		{ "stx", dis_store },		/* DIF_OP_STX */
3671a7c1b7mws		{ "uldsb", dis_load },		/* DIF_OP_ULDSB */
3681a7c1b7mws		{ "uldsh", dis_load },		/* DIF_OP_ULDSH */
3691a7c1b7mws		{ "uldsw", dis_load },		/* DIF_OP_ULDSW */
3701a7c1b7mws		{ "uldub", dis_load },		/* DIF_OP_ULDUB */
3711a7c1b7mws		{ "ulduh", dis_load },		/* DIF_OP_ULDUH */
3721a7c1b7mws		{ "ulduw", dis_load },		/* DIF_OP_ULDUW */
3731a7c1b7mws		{ "uldx", dis_load },		/* DIF_OP_ULDX */
3741a7c1b7mws		{ "rldsb", dis_load },		/* DIF_OP_RLDSB */
3751a7c1b7mws		{ "rldsh", dis_load },		/* DIF_OP_RLDSH */
3761a7c1b7mws		{ "rldsw", dis_load },		/* DIF_OP_RLDSW */
3771a7c1b7mws		{ "rldub", dis_load },		/* DIF_OP_RLDUB */
3781a7c1b7mws		{ "rlduh", dis_load },		/* DIF_OP_RLDUH */
3791a7c1b7mws		{ "rlduw", dis_load },		/* DIF_OP_RLDUW */
3801a7c1b7mws		{ "rldx", dis_load },		/* DIF_OP_RLDX */
3811a7c1b7mws		{ "xlate", dis_xlate },		/* DIF_OP_XLATE */
3821a7c1b7mws		{ "xlarg", dis_xlate },		/* DIF_OP_XLARG */
3831a7c1b7mws	};
3841a7c1b7mws
3851a7c1b7mws	dif_instr_t instr, opcode;
3861a7c1b7mws	const struct opent *op;
3871a7c1b7mws
3881a7c1b7mws	if (mdb_vread(&instr, sizeof (dif_instr_t), addr) == -1) {
3891a7c1b7mws		mdb_warn("failed to read DIF instruction at %p", addr);
3901a7c1b7mws		return (DCMD_ERR);
3911a7c1b7mws	}
3921a7c1b7mws
3931a7c1b7mws	opcode = DIF_INSTR_OP(instr);
3941a7c1b7mws
3951a7c1b7mws	if (opcode >= sizeof (optab) / sizeof (optab[0]))
3961a7c1b7mws		opcode = 0; /* force invalid opcode message */
3971a7c1b7mws
3981a7c1b7mws	op = &optab[opcode];
399187eccfbmc	mdb_printf("%0?p %08x ", addr, instr);
4001a7c1b7mws	op->op_func(dp, op->op_name, instr);
4011a7c1b7mws	mdb_printf("\n");
4021a7c1b7mws	mdb_set_dot(addr + sizeof (dif_instr_t));
4031a7c1b7mws
4041a7c1b7mws	return (DCMD_OK);
4051a7c1b7mws}
4061a7c1b7mws
4071a7c1b7mws/*ARGSUSED*/
4081a7c1b7mwsint
4091a7c1b7mwsdifo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4101a7c1b7mws{
4111a7c1b7mws	dtrace_difo_t difo, *dp = &difo;
4121a7c1b7mws	uintptr_t instr, limit;
4131a7c1b7mws	dtrace_difv_t *dvp;
4141a7c1b7mws	size_t varsize;
4151a7c1b7mws	ulong_t i;
4161a7c1b7mws	char type[64];
4171a7c1b7mws	char *str;
4181a7c1b7mws
4191a7c1b7mws	if (!(flags & DCMD_ADDRSPEC))
4201a7c1b7mws		return (DCMD_USAGE);
4211a7c1b7mws
4221a7c1b7mws	if (mdb_vread(dp, sizeof (dtrace_difo_t), addr) == -1) {
4231a7c1b7mws		mdb_warn("couldn't read dtrace_difo_t at %p", addr);
4241a7c1b7mws		return (DCMD_ERR);
4251a7c1b7mws	}
4261a7c1b7mws
4271a7c1b7mws	mdb_printf("%<u>DIF Object 0x%p%</u> (refcnt=%d)\n\n",
4281a7c1b7mws	    addr, dp->dtdo_refcnt);
429187eccfbmc	mdb_printf("%<b>%-?s %-8s %s%</b>\n", "ADDR", "OPCODE", "INSTRUCTION");
4301a7c1b7mws
4311a7c1b7mws	mdb_set_dot((uintmax_t)(uintptr_t)dp->dtdo_buf);
4321a7c1b7mws	limit = (uintptr_t)dp->dtdo_buf + dp->dtdo_len * sizeof (dif_instr_t);
4331a7c1b7mws
4341a7c1b7mws	while ((instr = mdb_get_dot()) < limit)
4351a7c1b7mws		dis(instr, dp);
4361a7c1b7mws
4371a7c1b7mws	if (dp->dtdo_varlen != 0) {
4381a7c1b7mws		mdb_printf("\n%<b>%-16s %-4s %-3s %-3s %-4s %s%</b>\n",
4391a7c1b7mws		    "NAME", "ID", "KND", "SCP", "FLAG", "TYPE");
4401a7c1b7mws	}
4411a7c1b7mws
4421a7c1b7mws	varsize = sizeof (dtrace_difv_t) * dp->dtdo_varlen;
4431a7c1b7mws	dvp = mdb_alloc(varsize, UM_SLEEP | UM_GC);
4441a7c1b7mws
4451a7c1b7mws	if (mdb_vread(dvp, varsize, (uintptr_t)dp->dtdo_vartab) == -1) {
4461a7c1b7mws		mdb_warn("couldn't read dtdo_vartab");
4471a7c1b7mws		return (DCMD_ERR);
4481a7c1b7mws	}
4491a7c1b7mws
4501a7c1b7mws	str = mdb_alloc(dp->dtdo_strlen, UM_SLEEP | UM_GC);
4511a7c1b7mws
4521a7c1b7mws	if (mdb_vread(str, dp->dtdo_strlen, (uintptr_t)dp->dtdo_strtab) == -1) {
4531a7c1b7mws		mdb_warn("couldn't read dtdo_strtab");
4541a7c1b7mws		return (DCMD_ERR);
4551a7c1b7mws	}
4561a7c1b7mws
4571a7c1b7mws	for (i = 0; i < dp->dtdo_varlen; i++) {
4581a7c1b7mws		dtrace_difv_t *v = &dvp[i];
4591a7c1b7mws		char kind[4], scope[4], flags[16] = { 0 };
4601a7c1b7mws
4611a7c1b7mws		switch (v->dtdv_kind) {
4621a7c1b7mws		case DIFV_KIND_ARRAY:
4631a7c1b7mws			(void) strcpy(kind, "arr");
4641a7c1b7mws			break;
4651a7c1b7mws		case DIFV_KIND_SCALAR:
4661a7c1b7mws			(void) strcpy(kind, "scl");
4671a7c1b7mws			break;
4681a7c1b7mws		default:
4691a7c1b7mws			(void) mdb_snprintf(kind, sizeof (kind),
4701a7c1b7mws			    "%u", v->dtdv_kind);
4711a7c1b7mws		}
4721a7c1b7mws
4731a7c1b7mws		switch (v->dtdv_scope) {
4741a7c1b7mws		case DIFV_SCOPE_GLOBAL:
4751a7c1b7mws			(void) strcpy(scope, "glb");
4761a7c1b7mws			break;
4771a7c1b7mws		case DIFV_SCOPE_THREAD:
4781a7c1b7mws			(void) strcpy(scope, "tls");
4791a7c1b7mws			break;
4801a7c1b7mws		case DIFV_SCOPE_LOCAL:
4811a7c1b7mws			(void) strcpy(scope, "loc");
4821a7c1b7mws			break;
4831a7c1b7mws		default:
4841a7c1b7mws			(void) mdb_snprintf(scope, sizeof (scope),
4851a7c1b7mws			    "%u", v->dtdv_scope);
4861a7c1b7mws		}
4871a7c1b7mws
4881a7c1b7mws		if (v->dtdv_flags & ~(DIFV_F_REF | DIFV_F_MOD)) {
4891a7c1b7mws			(void) mdb_snprintf(flags, sizeof (flags), "/0x%x",
4901a7c1b7mws			    v->dtdv_flags & ~(DIFV_F_REF | DIFV_F_MOD));
4911a7c1b7mws		}
4921a7c1b7mws
4931a7c1b7mws		if (v->dtdv_flags & DIFV_F_REF)
4941a7c1b7mws			(void) strcat(flags, "/r");
4951a7c1b7mws		if (v->dtdv_flags & DIFV_F_MOD)
4961a7c1b7mws			(void) strcat(flags, "/w");
4971a7c1b7mws
4981a7c1b7mws		mdb_printf("%-16s %-4x %-3s %-3s %-4s %s\n",
4991a7c1b7mws		    &str[v->dtdv_name],
500