xref: /onnv-gate/usr/src/cmd/mdb/common/modules/mdb_test/mdb_test.c (revision 436:c9ab97f06761)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*436Sdmick  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * MDB Regression Test Module
310Sstevel@tonic-gate  *
320Sstevel@tonic-gate  * This module contains dcmds and walkers that exercise various aspects of
330Sstevel@tonic-gate  * MDB and the MDB Module API.  It can be manually loaded and executed to
340Sstevel@tonic-gate  * verify that MDB is still working properly.
350Sstevel@tonic-gate  */
360Sstevel@tonic-gate 
370Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
380Sstevel@tonic-gate #define	_MDB
390Sstevel@tonic-gate #include <mdb/mdb_io_impl.h>
400Sstevel@tonic-gate #include <mdb/mdb.h>
410Sstevel@tonic-gate #undef _MDB
420Sstevel@tonic-gate 
430Sstevel@tonic-gate static int
cd_init(mdb_walk_state_t * wsp)440Sstevel@tonic-gate cd_init(mdb_walk_state_t *wsp)
450Sstevel@tonic-gate {
460Sstevel@tonic-gate 	wsp->walk_addr = 0xf;
470Sstevel@tonic-gate 	return (WALK_NEXT);
480Sstevel@tonic-gate }
490Sstevel@tonic-gate 
500Sstevel@tonic-gate static int
cd_step(mdb_walk_state_t * wsp)510Sstevel@tonic-gate cd_step(mdb_walk_state_t *wsp)
520Sstevel@tonic-gate {
530Sstevel@tonic-gate 	int status = wsp->walk_callback(wsp->walk_addr, NULL, wsp->walk_cbdata);
540Sstevel@tonic-gate 
550Sstevel@tonic-gate 	if (wsp->walk_addr-- == 0)
560Sstevel@tonic-gate 		return (WALK_DONE);
570Sstevel@tonic-gate 
580Sstevel@tonic-gate 	return (status);
590Sstevel@tonic-gate }
600Sstevel@tonic-gate 
610Sstevel@tonic-gate /*ARGSUSED*/
620Sstevel@tonic-gate static int
cmd_praddr(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)630Sstevel@tonic-gate cmd_praddr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
640Sstevel@tonic-gate {
650Sstevel@tonic-gate 	if ((flags != (DCMD_ADDRSPEC|DCMD_LOOP|DCMD_PIPE)) &&
660Sstevel@tonic-gate 	    (flags != (DCMD_ADDRSPEC|DCMD_LOOP|DCMD_PIPE|DCMD_LOOPFIRST))) {
670Sstevel@tonic-gate 		mdb_warn("ERROR: praddr invoked with flags = 0x%x\n", flags);
680Sstevel@tonic-gate 		return (DCMD_ERR);
690Sstevel@tonic-gate 	}
700Sstevel@tonic-gate 
710Sstevel@tonic-gate 	if (argc != 0) {
720Sstevel@tonic-gate 		mdb_warn("ERROR: praddr invoked with argc = %lu\n", argc);
730Sstevel@tonic-gate 		return (DCMD_ERR);
740Sstevel@tonic-gate 	}
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 	mdb_printf("%lr\n", addr);
770Sstevel@tonic-gate 	return (DCMD_OK);
780Sstevel@tonic-gate }
790Sstevel@tonic-gate 
800Sstevel@tonic-gate static int
compare(const void * lp,const void * rp)810Sstevel@tonic-gate compare(const void *lp, const void *rp)
820Sstevel@tonic-gate {
830Sstevel@tonic-gate 	uintptr_t lhs = *((const uintptr_t *)lp);
840Sstevel@tonic-gate 	uintptr_t rhs = *((const uintptr_t *)rp);
850Sstevel@tonic-gate 	return (lhs - rhs);
860Sstevel@tonic-gate }
870Sstevel@tonic-gate 
880Sstevel@tonic-gate /*ARGSUSED*/
890Sstevel@tonic-gate static int
cmd_qsort(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)900Sstevel@tonic-gate cmd_qsort(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
910Sstevel@tonic-gate {
920Sstevel@tonic-gate 	mdb_pipe_t p;
930Sstevel@tonic-gate 	size_t i;
940Sstevel@tonic-gate 
950Sstevel@tonic-gate 	if (flags != (DCMD_ADDRSPEC | DCMD_LOOP |
960Sstevel@tonic-gate 	    DCMD_LOOPFIRST | DCMD_PIPE | DCMD_PIPE_OUT)) {
970Sstevel@tonic-gate 		mdb_warn("ERROR: qsort invoked with flags = 0x%x\n", flags);
980Sstevel@tonic-gate 		return (DCMD_ERR);
990Sstevel@tonic-gate 	}
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 	if (argc != 0) {
1020Sstevel@tonic-gate 		mdb_warn("ERROR: qsort invoked with argc = %lu\n", argc);
1030Sstevel@tonic-gate 		return (DCMD_ERR);
1040Sstevel@tonic-gate 	}
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate 	mdb_get_pipe(&p);
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 	if (p.pipe_data == NULL || p.pipe_len != 16) {
1090Sstevel@tonic-gate 		mdb_warn("ERROR: qsort got bad results from mdb_get_pipe\n");
1100Sstevel@tonic-gate 		return (DCMD_ERR);
1110Sstevel@tonic-gate 	}
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 	if (p.pipe_data[0] != addr) {
1140Sstevel@tonic-gate 		mdb_warn("ERROR: qsort pipe_data[0] != addr\n");
1150Sstevel@tonic-gate 		return (DCMD_ERR);
1160Sstevel@tonic-gate 	}
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 	qsort(p.pipe_data, p.pipe_len, sizeof (uintptr_t), compare);
1190Sstevel@tonic-gate 	mdb_set_pipe(&p);
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	for (i = 0; i < 16; i++) {
1220Sstevel@tonic-gate 		if (p.pipe_data[i] != i) {
1230Sstevel@tonic-gate 			mdb_warn("ERROR: qsort got bad data in slot %lu\n", i);
1240Sstevel@tonic-gate 			return (DCMD_ERR);
1250Sstevel@tonic-gate 		}
1260Sstevel@tonic-gate 	}
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	return (DCMD_OK);
1290Sstevel@tonic-gate }
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate /*ARGSUSED*/
1320Sstevel@tonic-gate static int
cmd_runtest(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1330Sstevel@tonic-gate cmd_runtest(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1340Sstevel@tonic-gate {
1350Sstevel@tonic-gate 	mdb_walker_t w = { "count", "count", cd_init, cd_step, NULL };
1360Sstevel@tonic-gate 	int state, i;
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	mdb_printf("- adding countdown walker\n");
1390Sstevel@tonic-gate 	if (mdb_add_walker(&w) != 0) {
1400Sstevel@tonic-gate 		mdb_warn("ERROR: failed to add walker");
1410Sstevel@tonic-gate 		return (DCMD_ERR);
1420Sstevel@tonic-gate 	}
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	mdb_printf("- executing countdown pipeline\n");
1450Sstevel@tonic-gate 	if (mdb_eval("::walk mdb_test`count |::mdb_test`qsort |::praddr")) {
1460Sstevel@tonic-gate 		mdb_warn("ERROR: failed to eval command");
1470Sstevel@tonic-gate 		return (DCMD_ERR);
1480Sstevel@tonic-gate 	}
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 	mdb_printf("- removing countdown walker\n");
1510Sstevel@tonic-gate 	if (mdb_remove_walker("count") != 0) {
1520Sstevel@tonic-gate 		mdb_warn("ERROR: failed to remove walker");
1530Sstevel@tonic-gate 		return (DCMD_ERR);
1540Sstevel@tonic-gate 	}
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	state = mdb_get_state();
1570Sstevel@tonic-gate 	mdb_printf("- kernel=%d state=%d\n", mdb_prop_kernel, state);
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 	if (mdb_prop_kernel && (state == MDB_STATE_DEAD ||
1600Sstevel@tonic-gate 	    state == MDB_STATE_RUNNING)) {
1610Sstevel@tonic-gate 		mdb_printf("- exercising pipelines\n");
1620Sstevel@tonic-gate 		for (i = 0; i < 100; i++) {
1630Sstevel@tonic-gate 			if (mdb_eval("::walk proc p | ::map *. | ::grep .==0 "
1640Sstevel@tonic-gate 			    "| ::map <p | ::ps") != 0) {
1650Sstevel@tonic-gate 				mdb_warn("ERROR: failed to eval pipeline");
1660Sstevel@tonic-gate 				return (DCMD_ERR);
1670Sstevel@tonic-gate 			}
1680Sstevel@tonic-gate 		}
1690Sstevel@tonic-gate 	}
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	return (DCMD_OK);
1720Sstevel@tonic-gate }
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate static int
cmd_vread(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1750Sstevel@tonic-gate cmd_vread(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1760Sstevel@tonic-gate {
1770Sstevel@tonic-gate 	size_t nbytes;
1780Sstevel@tonic-gate 	ssize_t rbytes;
1790Sstevel@tonic-gate 	void *buf;
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || argc != 1)
1820Sstevel@tonic-gate 		return (DCMD_USAGE);
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 	if (argv->a_type == MDB_TYPE_STRING)
1850Sstevel@tonic-gate 		nbytes = (size_t)mdb_strtoull(argv->a_un.a_str);
1860Sstevel@tonic-gate 	else
1870Sstevel@tonic-gate 		nbytes = (size_t)argv->a_un.a_val;
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	buf = mdb_alloc(nbytes, UM_SLEEP | UM_GC);
1900Sstevel@tonic-gate 	rbytes = mdb_vread(buf, nbytes, addr);
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	if (rbytes >= 0) {
1930Sstevel@tonic-gate 		mdb_printf("mdb_vread of %lu bytes returned %ld\n",
1940Sstevel@tonic-gate 		    nbytes, rbytes);
1950Sstevel@tonic-gate 	} else
1960Sstevel@tonic-gate 		mdb_warn("mdb_vread returned %ld", rbytes);
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	return (DCMD_OK);
1990Sstevel@tonic-gate }
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate /*ARGSUSED*/
2020Sstevel@tonic-gate static int
cmd_pread(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)2030Sstevel@tonic-gate cmd_pread(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2040Sstevel@tonic-gate {
2050Sstevel@tonic-gate 	size_t nbytes;
2060Sstevel@tonic-gate 	ssize_t rbytes;
2070Sstevel@tonic-gate 	void *buf;
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || argc != 1)
2100Sstevel@tonic-gate 		return (DCMD_USAGE);
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	if (argv->a_type == MDB_TYPE_STRING)
2130Sstevel@tonic-gate 		nbytes = (size_t)mdb_strtoull(argv->a_un.a_str);
2140Sstevel@tonic-gate 	else
2150Sstevel@tonic-gate 		nbytes = (size_t)argv->a_un.a_val;
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	buf = mdb_alloc(nbytes, UM_SLEEP | UM_GC);
2180Sstevel@tonic-gate 	rbytes = mdb_pread(buf, nbytes, mdb_get_dot());
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	if (rbytes >= 0) {
2210Sstevel@tonic-gate 		mdb_printf("mdb_pread of %lu bytes returned %ld\n",
2220Sstevel@tonic-gate 		    nbytes, rbytes);
2230Sstevel@tonic-gate 	} else
2240Sstevel@tonic-gate 		mdb_warn("mdb_pread returned %ld", rbytes);
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	return (DCMD_OK);
2270Sstevel@tonic-gate }
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate /*ARGSUSED*/
2300Sstevel@tonic-gate static int
cmd_readsym(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)2310Sstevel@tonic-gate cmd_readsym(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2320Sstevel@tonic-gate {
2330Sstevel@tonic-gate 	size_t nbytes;
2340Sstevel@tonic-gate 	ssize_t rbytes;
2350Sstevel@tonic-gate 	void *buf;
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) || argc != 2 ||
2380Sstevel@tonic-gate 	    argv->a_type != MDB_TYPE_STRING)
2390Sstevel@tonic-gate 		return (DCMD_USAGE);
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	if (argv[1].a_type == MDB_TYPE_STRING)
2420Sstevel@tonic-gate 		nbytes = (size_t)mdb_strtoull(argv[1].a_un.a_str);
2430Sstevel@tonic-gate 	else
2440Sstevel@tonic-gate 		nbytes = (size_t)argv[1].a_un.a_val;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	buf = mdb_alloc(nbytes, UM_SLEEP | UM_GC);
2470Sstevel@tonic-gate 	rbytes = mdb_readsym(buf, nbytes, argv->a_un.a_str);
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	if (rbytes >= 0) {
2500Sstevel@tonic-gate 		mdb_printf("mdb_readsym of %lu bytes returned %ld\n",
2510Sstevel@tonic-gate 		    nbytes, rbytes);
2520Sstevel@tonic-gate 	} else
2530Sstevel@tonic-gate 		mdb_warn("mdb_readsym returned %ld", rbytes);
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	return (DCMD_OK);
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate static int
cmd_call_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)2590Sstevel@tonic-gate cmd_call_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2600Sstevel@tonic-gate {
2610Sstevel@tonic-gate 	const char *dcmd;
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 	if (argc < 1 || argv->a_type != MDB_TYPE_STRING)
2640Sstevel@tonic-gate 		return (DCMD_USAGE);
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	dcmd = argv->a_un.a_str;
2670Sstevel@tonic-gate 	argv++;
2680Sstevel@tonic-gate 	argc--;
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	if (mdb_call_dcmd(dcmd, addr, flags, argc, argv) == -1) {
2710Sstevel@tonic-gate 		mdb_warn("failed to execute %s", dcmd);
2720Sstevel@tonic-gate 		return (DCMD_ERR);
2730Sstevel@tonic-gate 	}
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	return (DCMD_OK);
2760Sstevel@tonic-gate }
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate /*ARGSUSED*/
2790Sstevel@tonic-gate static int
cmd_getsetdot(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)2800Sstevel@tonic-gate cmd_getsetdot(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2810Sstevel@tonic-gate {
2820Sstevel@tonic-gate 	if (argc != 0)
2830Sstevel@tonic-gate 		return (DCMD_USAGE);
2840Sstevel@tonic-gate 
285*436Sdmick 	mdb_set_dot(0x12345678feedbeefULL);
2860Sstevel@tonic-gate 
287*436Sdmick 	if (mdb_get_dot() != 0x12345678feedbeefULL) {
2880Sstevel@tonic-gate 		mdb_warn("mdb_get_dot() returned wrong value!\n");
2890Sstevel@tonic-gate 		return (DCMD_ERR);
2900Sstevel@tonic-gate 	}
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	return (DCMD_OK);
2930Sstevel@tonic-gate }
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate /*
2960Sstevel@tonic-gate  * kmdb doesn't export some of the symbols used by these tests - namely mdb and
2970Sstevel@tonic-gate  * mdb_iob_.*.  We therefore can't use these tests with kmdb.
2980Sstevel@tonic-gate  */
2990Sstevel@tonic-gate #ifndef _KMDB
3000Sstevel@tonic-gate static void
do_nputs_tests(const char * banner,uint_t flags,size_t rows,size_t cols,size_t ocols)3010Sstevel@tonic-gate do_nputs_tests(const char *banner, uint_t flags,
3020Sstevel@tonic-gate     size_t rows, size_t cols, size_t ocols)
3030Sstevel@tonic-gate {
3040Sstevel@tonic-gate 	uint_t oflags;
3050Sstevel@tonic-gate 	int i;
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	oflags = mdb_iob_getflags(mdb.m_out) &
3080Sstevel@tonic-gate 	    (MDB_IOB_AUTOWRAP | MDB_IOB_INDENT);
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	mdb_printf("%s:\n", banner);
3110Sstevel@tonic-gate 	for (i = 0; i < 8; i++)
3120Sstevel@tonic-gate 		mdb_printf("0123456789");
3130Sstevel@tonic-gate 	mdb_printf("\n");
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	mdb_iob_clrflags(mdb.m_out, MDB_IOB_AUTOWRAP | MDB_IOB_INDENT);
3160Sstevel@tonic-gate 	mdb_iob_setflags(mdb.m_out, flags);
3170Sstevel@tonic-gate 	mdb_iob_resize(mdb.m_out, rows, cols);
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	for (i = 0; i < 50; i++)
3200Sstevel@tonic-gate 		mdb_printf(" xx");
3210Sstevel@tonic-gate 	mdb_printf("\n");
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	mdb_iob_clrflags(mdb.m_out, flags);
3240Sstevel@tonic-gate 	mdb_iob_setflags(mdb.m_out, oflags);
3250Sstevel@tonic-gate 	mdb_iob_resize(mdb.m_out, rows, ocols);
3260Sstevel@tonic-gate }
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate /*ARGSUSED*/
3290Sstevel@tonic-gate static int
cmd_nputs(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)3300Sstevel@tonic-gate cmd_nputs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3310Sstevel@tonic-gate {
3320Sstevel@tonic-gate 	size_t rows = mdb.m_out->iob_rows;
3330Sstevel@tonic-gate 	size_t cols = mdb.m_out->iob_cols;
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	if (argc != 0)
3360Sstevel@tonic-gate 		return (DCMD_USAGE);
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
3390Sstevel@tonic-gate 		addr = cols;
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	do_nputs_tests("tests with (~WRAP, ~INDENT)",
3420Sstevel@tonic-gate 	    0, rows, addr, cols);
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	do_nputs_tests("tests with (WRAP, ~INDENT)",
3450Sstevel@tonic-gate 	    MDB_IOB_AUTOWRAP, rows, addr, cols);
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	do_nputs_tests("tests with (~WRAP, INDENT)",
3480Sstevel@tonic-gate 	    MDB_IOB_INDENT, rows, addr, cols);
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	do_nputs_tests("tests with (WRAP, INDENT)",
3510Sstevel@tonic-gate 	    MDB_IOB_AUTOWRAP | MDB_IOB_INDENT, rows, addr, cols);
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	return (DCMD_OK);
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate #endif
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate /*ARGSUSED*/
3580Sstevel@tonic-gate static int
cmd_printf(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)3590Sstevel@tonic-gate cmd_printf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3600Sstevel@tonic-gate {
3610Sstevel@tonic-gate 	if (argc != 2 || argv[0].a_type != MDB_TYPE_STRING)
3620Sstevel@tonic-gate 		return (DCMD_USAGE);
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 	if (argv[1].a_type == MDB_TYPE_STRING)
3650Sstevel@tonic-gate 		mdb_printf(argv[0].a_un.a_str, argv[1].a_un.a_str);
3660Sstevel@tonic-gate 	else
3670Sstevel@tonic-gate 		mdb_printf(argv[0].a_un.a_str, argv[1].a_un.a_val);
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	return (DCMD_OK);
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate /*ARGSUSED*/
3730Sstevel@tonic-gate static int
cmd_abort(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)3740Sstevel@tonic-gate cmd_abort(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3750Sstevel@tonic-gate {
3760Sstevel@tonic-gate 	mdb_printf("hello"); /* stuff something in stdout's buffer */
3770Sstevel@tonic-gate 	return (*((volatile int *)NULL));
3780Sstevel@tonic-gate }
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate static const mdb_dcmd_t dcmds[] = {
3810Sstevel@tonic-gate 	{ "runtest", NULL, "run MDB regression tests", cmd_runtest },
3820Sstevel@tonic-gate 	{ "qsort", NULL, "qsort addresses", cmd_qsort },
3830Sstevel@tonic-gate 	{ "praddr", NULL, "print addresses", cmd_praddr },
3840Sstevel@tonic-gate 	{ "vread", ":nbytes", "call mdb_vread", cmd_vread },
3850Sstevel@tonic-gate 	{ "pread", ":nbytes", "call mdb_pread", cmd_pread },
3860Sstevel@tonic-gate 	{ "readsym", "symbol nbytes", "call mdb_readsym", cmd_readsym },
3870Sstevel@tonic-gate 	{ "call_dcmd", "dcmd [ args ... ]", "call dcmd", cmd_call_dcmd },
3880Sstevel@tonic-gate 	{ "getsetdot", NULL, "test get and set dot", cmd_getsetdot },
3890Sstevel@tonic-gate #ifndef _KMDB
3900Sstevel@tonic-gate 	{ "nputs", "?", "test iob nputs engine", cmd_nputs },
3910Sstevel@tonic-gate #endif
3920Sstevel@tonic-gate 	{ "printf", "fmt arg", "test printf engine", cmd_printf },
3930Sstevel@tonic-gate 	{ "abort", NULL, "test unexpected dcmd abort", cmd_abort },
3940Sstevel@tonic-gate 	{ NULL }
3950Sstevel@tonic-gate };
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate static const mdb_walker_t walkers[] = {
3980Sstevel@tonic-gate 	{ "countdown", "count down from 16 to 0", cd_init, cd_step, NULL },
3990Sstevel@tonic-gate 	{ NULL }
4000Sstevel@tonic-gate };
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate const mdb_modinfo_t *
_mdb_init(void)4050Sstevel@tonic-gate _mdb_init(void)
4060Sstevel@tonic-gate {
4070Sstevel@tonic-gate 	return (&modinfo);
4080Sstevel@tonic-gate }
409