xref: /illumos-gate/usr/src/cmd/mdb/common/mdb/mdb_cmds.c (revision 48bc00d6)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/elf.h>
28 #include <sys/elf_SPARC.h>
29 
30 #include <libproc.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <alloca.h>
36 #include <libctf.h>
37 #include <ctype.h>
38 
39 #include <mdb/mdb_string.h>
40 #include <mdb/mdb_argvec.h>
41 #include <mdb/mdb_nv.h>
42 #include <mdb/mdb_fmt.h>
43 #include <mdb/mdb_target.h>
44 #include <mdb/mdb_err.h>
45 #include <mdb/mdb_debug.h>
46 #include <mdb/mdb_conf.h>
47 #include <mdb/mdb_module.h>
48 #include <mdb/mdb_modapi.h>
49 #include <mdb/mdb_stdlib.h>
50 #include <mdb/mdb_lex.h>
51 #include <mdb/mdb_io_impl.h>
52 #include <mdb/mdb_help.h>
53 #include <mdb/mdb_disasm.h>
54 #include <mdb/mdb_frame.h>
55 #include <mdb/mdb_evset.h>
56 #include <mdb/mdb_print.h>
57 #include <mdb/mdb_nm.h>
58 #include <mdb/mdb_set.h>
59 #include <mdb/mdb_demangle.h>
60 #include <mdb/mdb_ctf.h>
61 #include <mdb/mdb_whatis.h>
62 #include <mdb/mdb_whatis_impl.h>
63 #include <mdb/mdb_macalias.h>
64 #ifdef _KMDB
65 #include <kmdb/kmdb_kdi.h>
66 #endif
67 #include <mdb/mdb.h>
68 
69 #ifdef __sparc
70 #define	SETHI_MASK	0xc1c00000
71 #define	SETHI_VALUE	0x01000000
72 
73 #define	IS_SETHI(machcode)	(((machcode) & SETHI_MASK) == SETHI_VALUE)
74 
75 #define	OP(machcode)	((machcode) >> 30)
76 #define	OP3(machcode)	(((machcode) >> 19) & 0x3f)
77 #define	RD(machcode)	(((machcode) >> 25) & 0x1f)
78 #define	RS1(machcode)	(((machcode) >> 14) & 0x1f)
79 #define	I(machcode)	(((machcode) >> 13) & 0x01)
80 
81 #define	IMM13(machcode)	((machcode) & 0x1fff)
82 #define	IMM22(machcode)	((machcode) & 0x3fffff)
83 
84 #define	OP_ARITH_MEM_MASK	0x2
85 #define	OP_ARITH		0x2
86 #define	OP_MEM			0x3
87 
88 #define	OP3_CC_MASK		0x10
89 #define	OP3_COMPLEX_MASK	0x20
90 
91 #define	OP3_ADD			0x00
92 #define	OP3_OR			0x02
93 #define	OP3_XOR			0x03
94 
95 #ifndef	R_O7
96 #define	R_O7	0xf
97 #endif
98 #endif /* __sparc */
99 
100 static mdb_tgt_addr_t
101 write_uint8(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t ull, uint_t rdback)
102 {
103 	uint8_t o, n = (uint8_t)ull;
104 
105 	if (rdback && mdb_tgt_aread(mdb.m_target, as, &o, sizeof (o),
106 	    addr) == -1)
107 		return (addr);
108 
109 	if (mdb_tgt_awrite(mdb.m_target, as, &n, sizeof (n), addr) == -1)
110 		return (addr);
111 
112 	if (rdback) {
113 		if (mdb_tgt_aread(mdb.m_target, as, &n, sizeof (n), addr) == -1)
114 			return (addr);
115 
116 		mdb_iob_printf(mdb.m_out, "%-#*lla%16T%-#8x=%8T0x%x\n",
117 		    mdb_iob_getmargin(mdb.m_out), addr, o, n);
118 	}
119 
120 	return (addr + sizeof (n));
121 }
122 
123 static mdb_tgt_addr_t
124 write_uint16(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t ull, uint_t rdback)
125 {
126 	uint16_t o, n = (uint16_t)ull;
127 
128 	if (rdback && mdb_tgt_aread(mdb.m_target, as, &o, sizeof (o),
129 	    addr) == -1)
130 		return (addr);
131 
132 	if (mdb_tgt_awrite(mdb.m_target, as, &n, sizeof (n), addr) == -1)
133 		return (addr);
134 
135 	if (rdback) {
136 		if (mdb_tgt_aread(mdb.m_target, as, &n, sizeof (n), addr) == -1)
137 			return (addr);
138 
139 		mdb_iob_printf(mdb.m_out, "%-#*lla%16T%-#8hx=%8T0x%hx\n",
140 		    mdb_iob_getmargin(mdb.m_out), addr, o, n);
141 	}
142 
143 	return (addr + sizeof (n));
144 }
145 
146 static mdb_tgt_addr_t
147 write_uint32(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t ull, uint_t rdback)
148 {
149 	uint32_t o, n = (uint32_t)ull;
150 
151 	if (rdback && mdb_tgt_aread(mdb.m_target, as, &o, sizeof (o),
152 	    addr) == -1)
153 		return (addr);
154 
155 	if (mdb_tgt_awrite(mdb.m_target, as, &n, sizeof (n), addr) == -1)
156 		return (addr);
157 
158 	if (rdback) {
159 		if (mdb_tgt_aread(mdb.m_target, as, &n, sizeof (n), addr) == -1)
160 			return (addr);
161 
162 		mdb_iob_printf(mdb.m_out, "%-#*lla%16T%-#16x=%8T0x%x\n",
163 		    mdb_iob_getmargin(mdb.m_out), addr, o, n);
164 	}
165 
166 	return (addr + sizeof (n));
167 }
168 
169 static mdb_tgt_addr_t
170 write_uint64(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t n, uint_t rdback)
171 {
172 	uint64_t o;
173 
174 	if (rdback && mdb_tgt_aread(mdb.m_target, as, &o, sizeof (o),
175 	    addr) == -1)
176 		return (addr);
177 
178 	if (mdb_tgt_awrite(mdb.m_target, as, &n, sizeof (n), addr) == -1)
179 		return (addr);
180 
181 	if (rdback) {
182 		if (mdb_tgt_aread(mdb.m_target, as, &n, sizeof (n), addr) == -1)
183 			return (addr);
184 
185 		mdb_iob_printf(mdb.m_out, "%-#*lla%16T%-#24llx=%8T0x%llx\n",
186 		    mdb_iob_getmargin(mdb.m_out), addr, o, n);
187 	}
188 
189 	return (addr + sizeof (n));
190 }
191 
192 static int
193 write_arglist(mdb_tgt_as_t as, mdb_tgt_addr_t addr,
194     int argc, const mdb_arg_t *argv)
195 {
196 	mdb_tgt_addr_t (*write_value)(mdb_tgt_as_t, mdb_tgt_addr_t,
197 	    uint64_t, uint_t);
198 	mdb_tgt_addr_t naddr;
199 	uintmax_t value;
200 	int rdback = mdb.m_flags & MDB_FL_READBACK;
201 	size_t i;
202 
203 	if (argc == 1) {
204 		mdb_warn("expected value to write following %c\n",
205 		    argv->a_un.a_char);
206 		return (DCMD_ERR);
207 	}
208 
209 	switch (argv->a_un.a_char) {
210 	case 'v':
211 		write_value = write_uint8;
212 		break;
213 	case 'w':
214 		write_value = write_uint16;
215 		break;
216 	case 'W':
217 		write_value = write_uint32;
218 		break;
219 	case 'Z':
220 		write_value = write_uint64;
221 		break;
222 	}
223 
224 	for (argv++, i = 1; i < argc; i++, argv++) {
225 		if (argv->a_type == MDB_TYPE_CHAR) {
226 			mdb_warn("expected immediate value instead of '%c'\n",
227 			    argv->a_un.a_char);
228 			return (DCMD_ERR);
229 		}
230 
231 		if (argv->a_type == MDB_TYPE_STRING) {
232 			if (mdb_eval(argv->a_un.a_str) == -1) {
233 				mdb_warn("failed to write \"%s\"",
234 				    argv->a_un.a_str);
235 				return (DCMD_ERR);
236 			}
237 			value = mdb_nv_get_value(mdb.m_dot);
238 		} else
239 			value = argv->a_un.a_val;
240 
241 		mdb_nv_set_value(mdb.m_dot, addr);
242 
243 		if ((naddr = write_value(as, addr, value, rdback)) == addr) {
244 			mdb_warn("failed to write %llr at address 0x%llx",
245 			    value, addr);
246 			mdb.m_incr = 0;
247 			break;
248 		}
249 
250 		mdb.m_incr = naddr - addr;
251 		addr = naddr;
252 	}
253 
254 	return (DCMD_OK);
255 }
256 
257 static mdb_tgt_addr_t
258 match_uint16(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t v64, uint64_t m64)
259 {
260 	uint16_t x, val = (uint16_t)v64, mask = (uint16_t)m64;
261 
262 	for (; mdb_tgt_aread(mdb.m_target, as, &x,
263 	    sizeof (x), addr) == sizeof (x); addr += sizeof (x)) {
264 
265 		if ((x & mask) == val) {
266 			mdb_iob_printf(mdb.m_out, "%lla\n", addr);
267 			break;
268 		}
269 	}
270 	return (addr);
271 }
272 
273 static mdb_tgt_addr_t
274 match_uint32(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t v64, uint64_t m64)
275 {
276 	uint32_t x, val = (uint32_t)v64, mask = (uint32_t)m64;
277 
278 	for (; mdb_tgt_aread(mdb.m_target, as, &x,
279 	    sizeof (x), addr) == sizeof (x); addr += sizeof (x)) {
280 
281 		if ((x & mask) == val) {
282 			mdb_iob_printf(mdb.m_out, "%lla\n", addr);
283 			break;
284 		}
285 	}
286 	return (addr);
287 }
288 
289 static mdb_tgt_addr_t
290 match_uint64(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t val, uint64_t mask)
291 {
292 	uint64_t x;
293 
294 	for (; mdb_tgt_aread(mdb.m_target, as, &x,
295 	    sizeof (x), addr) == sizeof (x); addr += sizeof (x)) {
296 
297 		if ((x & mask) == val) {
298 			mdb_iob_printf(mdb.m_out, "%lla\n", addr);
299 			break;
300 		}
301 	}
302 	return (addr);
303 }
304 
305 static int
306 match_arglist(mdb_tgt_as_t as, uint_t flags, mdb_tgt_addr_t addr,
307     int argc, const mdb_arg_t *argv)
308 {
309 	mdb_tgt_addr_t (*match_value)(mdb_tgt_as_t, mdb_tgt_addr_t,
310 	    uint64_t, uint64_t);
311 
312 	uint64_t args[2] = { 0, -1ULL }; /* [ value, mask ] */
313 	size_t i;
314 
315 	if (argc < 2) {
316 		mdb_warn("expected value following %c\n", argv->a_un.a_char);
317 		return (DCMD_ERR);
318 	}
319 
320 	if (argc > 3) {
321 		mdb_warn("only value and mask may follow %c\n",
322 		    argv->a_un.a_char);
323 		return (DCMD_ERR);
324 	}
325 
326 	switch (argv->a_un.a_char) {
327 	case 'l':
328 		match_value = match_uint16;
329 		break;
330 	case 'L':
331 		match_value = match_uint32;
332 		break;
333 	case 'M':
334 		match_value = match_uint64;
335 		break;
336 	}
337 
338 	for (argv++, i = 1; i < argc; i++, argv++) {
339 		if (argv->a_type == MDB_TYPE_CHAR) {
340 			mdb_warn("expected immediate value instead of '%c'\n",
341 			    argv->a_un.a_char);
342 			return (DCMD_ERR);
343 		}
344 
345 		if (argv->a_type == MDB_TYPE_STRING) {
346 			if (mdb_eval(argv->a_un.a_str) == -1) {
347 				mdb_warn("failed to evaluate \"%s\"",
348 				    argv->a_un.a_str);
349 				return (DCMD_ERR);
350 			}
351 			args[i - 1] = mdb_nv_get_value(mdb.m_dot);
352 		} else
353 			args[i - 1] = argv->a_un.a_val;
354 	}
355 
356 	addr = match_value(as, addr, args[0], args[1]);
357 	mdb_nv_set_value(mdb.m_dot, addr);
358 
359 	/*
360 	 * In adb(1), the match operators ignore any repeat count that has
361 	 * been applied to them.  We emulate this undocumented property
362 	 * by returning DCMD_ABORT if our input is not a pipeline.
363 	 */
364 	return ((flags & DCMD_PIPE) ? DCMD_OK : DCMD_ABORT);
365 }
366 
367 static int
368 argncmp(int argc, const mdb_arg_t *argv, const char *s)
369 {
370 	for (; *s != '\0'; s++, argc--, argv++) {
371 		if (argc == 0 || argv->a_type != MDB_TYPE_CHAR)
372 			return (FALSE);
373 		if (argv->a_un.a_char != *s)
374 			return (FALSE);
375 	}
376 	return (TRUE);
377 }
378 
379 static int
380 print_arglist(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint_t flags,
381     int argc, const mdb_arg_t *argv)
382 {
383 	char buf[MDB_TGT_SYM_NAMLEN];
384 	mdb_tgt_addr_t oaddr = addr;
385 	mdb_tgt_addr_t naddr;
386 	GElf_Sym sym;
387 	size_t i, n;
388 
389 	if (DCMD_HDRSPEC(flags) && (flags & DCMD_PIPE_OUT) == 0) {
390 		const char *fmt;
391 		int is_dis;
392 		/*
393 		 * This is nasty, but necessary for precise adb compatibility.
394 		 * Detect disassembly format by looking for "ai" or "ia":
395 		 */
396 		if (argncmp(argc, argv, "ai")) {
397 			fmt = "%-#*lla\n";
398 			is_dis = TRUE;
399 		} else if (argncmp(argc, argv, "ia")) {
400 			fmt = "%-#*lla";
401 			is_dis = TRUE;
402 		} else {
403 			fmt = "%-#*lla%16T";
404 			is_dis = FALSE;
405 		}
406 
407 		/*
408 		 * If symbolic decoding is on, disassembly is off, and the
409 		 * address exactly matches a symbol, print the symbol name:
410 		 */
411 		if ((mdb.m_flags & MDB_FL_PSYM) && !is_dis &&
412 		    (as == MDB_TGT_AS_VIRT || as == MDB_TGT_AS_FILE) &&
413 		    mdb_tgt_lookup_by_addr(mdb.m_target, (uintptr_t)addr,
414 		    MDB_TGT_SYM_EXACT, buf, sizeof (buf), &sym, NULL) == 0)
415 			mdb_iob_printf(mdb.m_out, "%s:\n", buf);
416 
417 		/*
418 		 * If this is a virtual address, cast it so that it reflects
419 		 * only the valid component of the address.
420 		 */
421 		if (as == MDB_TGT_AS_VIRT)
422 			addr = (uintptr_t)addr;
423 
424 		mdb_iob_printf(mdb.m_out, fmt,
425 		    (uint_t)mdb_iob_getmargin(mdb.m_out), addr);
426 	}
427 
428 	if (argc == 0) {
429 		/*
430 		 * Yes, for you trivia buffs: if you use a format verb and give
431 		 * no format string, you get: X^"= "i ... note that in adb the
432 		 * the '=' verb once had 'z' as its default, but then 'z' was
433 		 * deleted (it was once an alias for 'i') and so =\n now calls
434 		 * scanform("z") and produces a 'bad modifier' message.
435 		 */
436 		static const mdb_arg_t def_argv[] = {
437 			{ MDB_TYPE_CHAR, MDB_INIT_CHAR('X') },
438 			{ MDB_TYPE_CHAR, MDB_INIT_CHAR('^') },
439 			{ MDB_TYPE_STRING, MDB_INIT_STRING("= ") },
440 			{ MDB_TYPE_CHAR, MDB_INIT_CHAR('i') }
441 		};
442 
443 		argc = sizeof (def_argv) / sizeof (mdb_arg_t);
444 		argv = def_argv;
445 	}
446 
447 	mdb_iob_setflags(mdb.m_out, MDB_IOB_INDENT);
448 
449 	for (i = 0, n = 1; i < argc; i++, argv++) {
450 		switch (argv->a_type) {
451 		case MDB_TYPE_CHAR:
452 			naddr = mdb_fmt_print(mdb.m_target, as, addr, n,
453 			    argv->a_un.a_char);
454 			mdb.m_incr = naddr - addr;
455 			addr = naddr;
456 			n = 1;
457 			break;
458 
459 		case MDB_TYPE_IMMEDIATE:
460 			n = argv->a_un.a_val;
461 			break;
462 
463 		case MDB_TYPE_STRING:
464 			mdb_iob_puts(mdb.m_out, argv->a_un.a_str);
465 			n = 1;
466 			break;
467 		}
468 	}
469 
470 	mdb.m_incr = addr - oaddr;
471 	mdb_iob_clrflags(mdb.m_out, MDB_IOB_INDENT);
472 	return (DCMD_OK);
473 }
474 
475 static int
476 print_common(mdb_tgt_as_t as, uint_t flags, int argc, const mdb_arg_t *argv)
477 {
478 	mdb_tgt_addr_t addr = mdb_nv_get_value(mdb.m_dot);
479 
480 	if (argc != 0 && argv->a_type == MDB_TYPE_CHAR) {
481 		if (strchr("vwWZ", argv->a_un.a_char))
482 			return (write_arglist(as, addr, argc, argv));
483 		if (strchr("lLM", argv->a_un.a_char))
484 			return (match_arglist(as, flags, addr, argc, argv));
485 	}
486 
487 	return (print_arglist(as, addr, flags, argc, argv));
488 }
489 
490 /*ARGSUSED*/
491 static int
492 cmd_print_core(uintptr_t x, uint_t flags, int argc, const mdb_arg_t *argv)
493 {
494 	return (print_common(MDB_TGT_AS_VIRT, flags, argc, argv));
495 }
496 
497 #ifndef _KMDB
498 /*ARGSUSED*/
499 static int
500 cmd_print_object(uintptr_t x, uint_t flags, int argc, const mdb_arg_t *argv)
501 {
502 	return (print_common(MDB_TGT_AS_FILE, flags, argc, argv));
503 }
504 #endif
505 
506 /*ARGSUSED*/
507 static int
508 cmd_print_phys(uintptr_t x, uint_t flags, int argc, const mdb_arg_t *argv)
509 {
510 	return (print_common(MDB_TGT_AS_PHYS, flags, argc, argv));
511 }
512 
513 /*ARGSUSED*/
514 static int
515 cmd_print_value(uintptr_t addr, uint_t flags,
516 	int argc, const mdb_arg_t *argv)
517 {
518 	uintmax_t ndot, dot = mdb_get_dot();
519 	const char *tgt_argv[1];
520 	mdb_tgt_t *t;
521 	size_t i, n;
522 
523 	if (argc == 0) {
524 		mdb_warn("expected one or more format characters "
525 		    "following '='\n");
526 		return (DCMD_ERR);
527 	}
528 
529 	tgt_argv[0] = (const char *)&dot;
530 	t = mdb_tgt_create(mdb_value_tgt_create, 0, 1, tgt_argv);
531 	mdb_iob_setflags(mdb.m_out, MDB_IOB_INDENT);
532 
533 	for (i = 0, n = 1; i < argc; i++, argv++) {
534 		switch (argv->a_type) {
535 		case MDB_TYPE_CHAR:
536 			ndot = mdb_fmt_print(t, MDB_TGT_AS_VIRT,
537 			    dot, n, argv->a_un.a_char);
538 			if (argv->a_un.a_char == '+' ||
539 			    argv->a_un.a_char == '-')
540 				dot = ndot;
541 			n = 1;
542 			break;
543 
544 		case MDB_TYPE_IMMEDIATE:
545 			n = argv->a_un.a_val;
546 			break;
547 
548 		case MDB_TYPE_STRING:
549 			mdb_iob_puts(mdb.m_out, argv->a_un.a_str);
550 			n = 1;
551 			break;
552 		}
553 	}
554 
555 	mdb_iob_clrflags(mdb.m_out, MDB_IOB_INDENT);
556 	mdb_nv_set_value(mdb.m_dot, dot);
557 	mdb.m_incr = 0;
558 
559 	mdb_tgt_destroy(t);
560 	return (DCMD_OK);
561 }
562 
563 /*ARGSUSED*/
564 static int
565 cmd_assign_variable(uintptr_t addr, uint_t flags,
566     int argc, const mdb_arg_t *argv)
567 {
568 	uintmax_t dot = mdb_nv_get_value(mdb.m_dot);
569 	const char *p;
570 	mdb_var_t *v;
571 
572 	if (argc == 2) {
573 		if (argv->a_type != MDB_TYPE_CHAR) {
574 			mdb_warn("improper arguments following '>' operator\n");
575 			return (DCMD_ERR);
576 		}
577 
578 		switch (argv->a_un.a_char) {
579 		case 'c':
580 			addr = *((uchar_t *)&addr);
581 			break;
582 		case 's':
583 			addr = *((ushort_t *)&addr);
584 			break;
585 		case 'i':
586 			addr = *((uint_t *)&addr);
587 			break;
588 		case 'l':
589 			addr = *((ulong_t *)&addr);
590 			break;
591 		default:
592 			mdb_warn("%c is not a valid // modifier\n",
593 			    argv->a_un.a_char);
594 			return (DCMD_ERR);
595 		}
596 
597 		dot = addr;
598 		argv++;
599 		argc--;
600 	}
601 
602 	if (argc != 1 || argv->a_type != MDB_TYPE_STRING) {
603 		mdb_warn("expected single variable name following '>'\n");
604 		return (DCMD_ERR);
605 	}
606 
607 	if (strlen(argv->a_un.a_str) >= (size_t)MDB_NV_NAMELEN) {
608 		mdb_warn("variable names may not exceed %d characters\n",
609 		    MDB_NV_NAMELEN - 1);
610 		return (DCMD_ERR);
611 	}
612 
613 	if ((p = strbadid(argv->a_un.a_str)) != NULL) {
614 		mdb_warn("'%c' may not be used in a variable name\n", *p);
615 		return (DCMD_ERR);
616 	}
617 
618 	if ((v = mdb_nv_lookup(&mdb.m_nv, argv->a_un.a_str)) == NULL)
619 		(void) mdb_nv_insert(&mdb.m_nv, argv->a_un.a_str, NULL, dot, 0);
620 	else
621 		mdb_nv_set_value(v, dot);
622 
623 	mdb.m_incr = 0;
624 	return (DCMD_OK);
625 }
626 
627 static int
628 print_soutype(const char *sou, uintptr_t addr, uint_t flags)
629 {
630 	static const char *prefixes[] = { "struct ", "union " };
631 	size_t namesz = 7 + strlen(sou) + 1;
632 	char *name = mdb_alloc(namesz, UM_SLEEP | UM_GC);
633 	mdb_ctf_id_t id;
634 	int i;
635 
636 	for (i = 0; i < 2; i++) {
637 		(void) mdb_snprintf(name, namesz, "%s%s", prefixes[i], sou);
638 
639 		if (mdb_ctf_lookup_by_name(name, &id) == 0) {
640 			mdb_arg_t v;
641 			int rv;
642 
643 			v.a_type = MDB_TYPE_STRING;
644 			v.a_un.a_str = name;
645 
646 			rv = mdb_call_dcmd("print", addr, flags, 1, &v);
647 			return (rv);
648 		}
649 	}
650 
651 	return (DCMD_ERR);
652 }
653 
654 static int
655 print_type(const char *name, uintptr_t addr, uint_t flags)
656 {
657 	mdb_ctf_id_t id;
658 	char *sname;
659 	size_t snamesz;
660 	int rv;
661 
662 	if (!(flags & DCMD_ADDRSPEC)) {
663 		addr = mdb_get_dot();
664 		flags |= DCMD_ADDRSPEC;
665 	}
666 
667 	if ((rv = print_soutype(name, addr, flags)) != DCMD_ERR)
668 		return (rv);
669 
670 	snamesz = strlen(name) + 3;
671 	sname = mdb_zalloc(snamesz, UM_SLEEP | UM_GC);
672 	(void) mdb_snprintf(sname, snamesz, "%s_t", name);
673 
674 	if (mdb_ctf_lookup_by_name(sname, &id) == 0) {
675 		mdb_arg_t v;
676 		int rv;
677 
678 		v.a_type = MDB_TYPE_STRING;
679 		v.a_un.a_str = sname;
680 
681 		rv = mdb_call_dcmd("print", addr, flags, 1, &v);
682 		return (rv);
683 	}
684 
685 	sname[snamesz - 2] = 's';
686 	rv = print_soutype(sname, addr, flags);
687 	return (rv);
688 }
689 
690 static int
691 exec_alias(const char *fname, uintptr_t addr, uint_t flags)
692 {
693 	const char *alias;
694 	int rv;
695 
696 	if ((alias = mdb_macalias_lookup(fname)) == NULL)
697 		return (DCMD_ERR);
698 
699 	if (flags & DCMD_ADDRSPEC) {
700 		size_t sz = sizeof (uintptr_t) * 2 + strlen(alias) + 1;
701 		char *addralias = mdb_alloc(sz, UM_SLEEP | UM_GC);
702 		(void) mdb_snprintf(addralias, sz, "%p%s", addr, alias);
703 		rv = mdb_eval(addralias);
704 	} else {
705 		rv = mdb_eval(alias);
706 	}
707 
708 	return (rv == -1 ? DCMD_ABORT : DCMD_OK);
709 }
710 
711 /*ARGSUSED*/
712 static int
713 cmd_src_file(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
714 {
715 	const char *fname;
716 	mdb_io_t *fio;
717 	int rv;
718 
719 	if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
720 		return (DCMD_USAGE);
721 
722 	fname = argv->a_un.a_str;
723 
724 	if (flags & DCMD_PIPE_OUT) {
725 		mdb_warn("macro files cannot be used as input to a pipeline\n");
726 		return (DCMD_ABORT);
727 	}
728 
729 	if ((fio = mdb_fdio_create_path(mdb.m_ipath, fname,
730 	    O_RDONLY, 0)) != NULL) {
731 		mdb_frame_t *fp = mdb.m_frame;
732 		int err;
733 
734 		mdb_iob_stack_push(&fp->f_istk, mdb.m_in, yylineno);
735 		mdb.m_in = mdb_iob_create(fio, MDB_IOB_RDONLY);
736 		err = mdb_run();
737 
738 		ASSERT(fp == mdb.m_frame);
739 		mdb.m_in = mdb_iob_stack_pop(&fp->f_istk);
740 		yylineno = mdb_iob_lineno(mdb.m_in);
741 
742 		if (err == MDB_ERR_PAGER && mdb.m_fmark != fp)
743 			longjmp(fp->f_pcb, err);
744 
745 		if (err == MDB_ERR_QUIT || err == MDB_ERR_ABORT ||
746 		    err == MDB_ERR_SIGINT || err == MDB_ERR_OUTPUT)
747 			longjmp(fp->f_pcb, err);
748 
749 		return (DCMD_OK);
750 	}
751 
752 	if ((rv = exec_alias(fname, addr, flags)) != DCMD_ERR ||
753 	    (rv = print_type(fname, addr, flags)) != DCMD_ERR)
754 		return (rv);
755 
756 	mdb_warn("failed to open %s (see ::help '$<')\n", fname);
757 	return (DCMD_ABORT);
758 }
759 
760 static int
761 cmd_exec_file(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
762 {
763 	const char *fname;
764 	mdb_io_t *fio;
765 	int rv;
766 
767 	/*
768 	 * The syntax [expr[,count]]$< with no trailing macro file name is
769 	 * magic in that if count is zero, this command won't be called and
770 	 * the expression is thus a no-op.  If count is non-zero, we get
771 	 * invoked with argc == 0, and this means abort the current macro.
772 	 * If our debugger stack depth is greater than one, we may be using
773 	 * $< from within a previous $<<, so in that case we set m_in to
774 	 * NULL to force this entire frame to be popped.
775 	 */
776 	if (argc == 0) {
777 		if (mdb_iob_stack_size(&mdb.m_frame->f_istk) != 0) {
778 			mdb_iob_destroy(mdb.m_in);
779 			mdb.m_in = mdb_iob_stack_pop(&mdb.m_frame->f_istk);
780 		} else if (mdb.m_depth > 1) {
781 			mdb_iob_destroy(mdb.m_in);
782 			mdb.m_in = NULL;
783 		} else
784 			mdb_warn("input stack is empty\n");
785 		return (DCMD_OK);
786 	}
787 
788 	if ((flags & (DCMD_PIPE | DCMD_PIPE_OUT)) || mdb.m_depth == 1)
789 		return (cmd_src_file(addr, flags, argc, argv));
790 
791 	if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
792 		return (DCMD_USAGE);
793 
794 	fname = argv->a_un.a_str;
795 
796 	if ((fio = mdb_fdio_create_path(mdb.m_ipath, fname,
797 	    O_RDONLY, 0)) != NULL) {
798 		mdb_iob_destroy(mdb.m_in);
799 		mdb.m_in = mdb_iob_create(fio, MDB_IOB_RDONLY);
800 		return (DCMD_OK);
801 	}
802 
803 	if ((rv = exec_alias(fname, addr, flags)) != DCMD_ERR ||
804 	    (rv = print_type(fname, addr, flags)) != DCMD_ERR)
805 		return (rv);
806 
807 	mdb_warn("failed to open %s (see ::help '$<')\n", fname);
808 	return (DCMD_ABORT);
809 }
810 
811 #ifndef _KMDB
812 /*ARGSUSED*/
813 static int
814 cmd_cat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
815 {
816 	int status = DCMD_OK;
817 	char buf[BUFSIZ];
818 	mdb_iob_t *iob;
819 	mdb_io_t *fio;
820 
821 	if (flags & DCMD_ADDRSPEC)
822 		return (DCMD_USAGE);
823 
824 	for (; argc-- != 0; argv++) {
825 		if (argv->a_type != MDB_TYPE_STRING) {
826 			mdb_warn("expected string argument\n");
827 			status = DCMD_ERR;
828 			continue;
829 		}
830 
831 		if ((fio = mdb_fdio_create_path(NULL,
832 		    argv->a_un.a_str, O_RDONLY, 0)) == NULL) {
833 			mdb_warn("failed to open %s", argv->a_un.a_str);
834 			status = DCMD_ERR;
835 			continue;
836 		}
837 
838 		iob = mdb_iob_create(fio, MDB_IOB_RDONLY);
839 
840 		while (!(mdb_iob_getflags(iob) & (MDB_IOB_EOF | MDB_IOB_ERR))) {
841 			ssize_t len = mdb_iob_read(iob, buf, sizeof (buf));
842 			if (len > 0) {
843 				if (mdb_iob_write(mdb.m_out, buf, len) < 0) {
844 					if (errno != EPIPE)
845 						mdb_warn("write failed");
846 					status = DCMD_ERR;
847 					break;
848 				}
849 			}
850 		}
851 
852 		if (mdb_iob_err(iob))
853 			mdb_warn("error while reading %s", mdb_iob_name(iob));
854 
855 		mdb_iob_destroy(iob);
856 	}
857 
858 	return (status);
859 }
860 #endif
861 
862 /*ARGSUSED*/
863 static int
864 cmd_grep(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
865 {
866 	if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
867 		return (DCMD_USAGE);
868 
869 	if (mdb_eval(argv->a_un.a_str) == -1)
870 		return (DCMD_ABORT);
871 
872 	if (mdb_get_dot() != 0)
873 		mdb_printf("%lr\n", addr);
874 
875 	return (DCMD_OK);
876 }
877 
878 /*ARGSUSED*/
879 static int
880 cmd_map(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
881 {
882 	if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
883 		return (DCMD_USAGE);
884 
885 	if (mdb_eval(argv->a_un.a_str) == -1)
886 		return (DCMD_ABORT);
887 
888 	mdb_printf("%llr\n", mdb_get_dot());
889 	return (DCMD_OK);
890 }
891 
892 /*ARGSUSED*/
893 static int
894 cmd_notsup(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
895 {
896 	mdb_warn("command is not supported by current target\n");
897 	return (DCMD_ERR);
898 }
899 
900 /*ARGSUSED*/
901 static int
902 cmd_quit(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
903 {
904 #ifdef _KMDB
905 	uint_t opt_u = FALSE;
906 
907 	if (mdb_getopts(argc, argv,
908 	    'u', MDB_OPT_SETBITS, TRUE, &opt_u, NULL) != argc)
909 		return (DCMD_USAGE);
910 
911 	if (opt_u) {
912 		if (mdb.m_flags & MDB_FL_NOUNLOAD) {
913 			warn("%s\n", mdb_strerror(EMDB_KNOUNLOAD));
914 			return (DCMD_ERR);
915 		}
916 
917 		kmdb_kdi_set_unload_request();
918 	}
919 #endif
920 
921 	longjmp(mdb.m_frame->f_pcb, MDB_ERR_QUIT);
922 	/*NOTREACHED*/
923 	return (DCMD_ERR);
924 }
925 
926 #ifdef _KMDB
927 static void
928 quit_help(void)
929 {
930 	mdb_printf(
931 	    "-u    unload the debugger (if not loaded at boot)\n");
932 }
933 #endif
934 
935 /*ARGSUSED*/
936 static int
937 cmd_vars(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
938 {
939 	uint_t opt_nz = FALSE, opt_tag = FALSE, opt_prt = FALSE;
940 	mdb_var_t *v;
941 
942 	if (mdb_getopts(argc, argv,
943 	    'n', MDB_OPT_SETBITS, TRUE, &opt_nz,
944 	    'p', MDB_OPT_SETBITS, TRUE, &opt_prt,
945 	    't', MDB_OPT_SETBITS, TRUE, &opt_tag, NULL) != argc)
946 		return (DCMD_USAGE);
947 
948 	mdb_nv_rewind(&mdb.m_nv);
949 
950 	while ((v = mdb_nv_advance(&mdb.m_nv)) != NULL) {
951 		if ((opt_tag == FALSE || (v->v_flags & MDB_NV_TAGGED)) &&
952 		    (opt_nz == FALSE || mdb_nv_get_value(v) != 0)) {
953 			if (opt_prt) {
954 				mdb_printf("%#llr>%s\n",
955 				    mdb_nv_get_value(v), mdb_nv_get_name(v));
956 			} else {
957 				mdb_printf("%s = %llr\n",
958 				    mdb_nv_get_name(v), mdb_nv_get_value(v));
959 			}
960 		}
961 	}
962 
963 	return (DCMD_OK);
964 }
965 
966 /*ARGSUSED*/
967 static int
968 cmd_nzvars(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
969 {
970 	uintmax_t value;
971 	mdb_var_t *v;
972 
973 	if (argc != 0)
974 		return (DCMD_USAGE);
975 
976 	mdb_nv_rewind(&mdb.m_nv);
977 
978 	while ((v = mdb_nv_advance(&mdb.m_nv)) != NULL) {
979 		if ((value = mdb_nv_get_value(v)) != 0)
980 			mdb_printf("%s = %llr\n", mdb_nv_get_name(v), value);
981 	}
982 
983 	return (DCMD_OK);
984 }
985 
986 /*ARGSUSED*/
987 static int
988 cmd_radix(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
989 {
990 	if (argc != 0)
991 		return (DCMD_USAGE);
992 
993 	if (flags & DCMD_ADDRSPEC) {
994 		if (addr < 2 || addr > 16) {
995 			mdb_warn("expected radix from 2 to 16\n");
996 			return (DCMD_ERR);
997 		}
998 		mdb.m_radix = (int)addr;
999 	}
1000 
1001 	mdb_iob_printf(mdb.m_out, "radix = %d base ten\n", mdb.m_radix);
1002 	return (DCMD_OK);
1003 }
1004 
1005 /*ARGSUSED*/
1006 static int
1007 cmd_symdist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1008 {
1009 	if (argc != 0)
1010 		return (DCMD_USAGE);
1011 
1012 	if (flags & DCMD_ADDRSPEC)
1013 		mdb.m_symdist = addr;
1014 
1015 	mdb_printf("symbol matching distance = %lr (%s)\n",
1016 	    mdb.m_symdist, mdb.m_symdist ? "absolute mode" : "smart mode");
1017 
1018 	return (DCMD_OK);
1019 }
1020 
1021 /*ARGSUSED*/
1022 static int
1023 cmd_pgwidth(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1024 {
1025 	if (argc != 0)
1026 		return (DCMD_USAGE);
1027 
1028 	if (flags & DCMD_ADDRSPEC)
1029 		mdb_iob_resize(mdb.m_out, mdb.m_out->iob_rows, addr);
1030 
1031 	mdb_printf("output page width = %lu\n", mdb.m_out->iob_cols);
1032 	return (DCMD_OK);
1033 }
1034 
1035 /*ARGSUSED*/
1036 static int
1037 cmd_reopen(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1038 {
1039 	if (argc != 0)
1040 		return (DCMD_USAGE);
1041 
1042 	if (mdb_tgt_setflags(mdb.m_target, MDB_TGT_F_RDWR) == -1) {
1043 		mdb_warn("failed to re-open target for writing");
1044 		return (DCMD_ERR);
1045 	}
1046 
1047 	return (DCMD_OK);
1048 }
1049 
1050 /*ARGSUSED*/
1051 static int
1052 print_xdata(void *ignored, const char *name, const char *desc, size_t nbytes)
1053 {
1054 	mdb_printf("%-24s - %s (%lu bytes)\n", name, desc, (ulong_t)nbytes);
1055 	return (0);
1056 }
1057 
1058 /*ARGSUSED*/
1059 static int
1060 cmd_xdata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1061 {
1062 	if (argc != 0 || (flags & DCMD_ADDRSPEC))
1063 		return (DCMD_USAGE);
1064 
1065 	(void) mdb_tgt_xdata_iter(mdb.m_target, print_xdata, NULL);
1066 	return (DCMD_OK);
1067 }
1068 
1069 /*ARGSUSED*/
1070 static int
1071 cmd_unset(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1072 {
1073 	mdb_var_t *v;
1074 	size_t i;
1075 
1076 	for (i = 0; i < argc; i++) {
1077 		if (argv[i].a_type != MDB_TYPE_STRING) {
1078 			mdb_warn("bad option: arg %lu is not a string\n",
1079 			    (ulong_t)i + 1);
1080 			return (DCMD_USAGE);
1081 		}
1082 	}
1083 
1084 	for (i = 0; i < argc; i++, argv++) {
1085 		if ((v = mdb_nv_lookup(&mdb.m_nv, argv->a_un.a_str)) == NULL)
1086 			mdb_warn("variable '%s' not defined\n",
1087 			    argv->a_un.a_str);
1088 		else
1089 			mdb_nv_remove(&mdb.m_nv, v);
1090 	}
1091 
1092 	return (DCMD_OK);
1093 }
1094 
1095 #ifndef _KMDB
1096 /*ARGSUSED*/
1097 static int
1098 cmd_log(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1099 {
1100 	uint_t opt_e = FALSE, opt_d = FALSE;
1101 	const char *filename = NULL;
1102 	int i;
1103 
1104 	i = mdb_getopts(argc, argv,
1105 	    'd', MDB_OPT_SETBITS, TRUE, &opt_d,
1106 	    'e', MDB_OPT_SETBITS, TRUE, &opt_e, NULL);
1107 
1108 	if ((i != argc && i != argc - 1) || (opt_d && opt_e) ||
1109 	    (i != argc && argv[i].a_type != MDB_TYPE_STRING) ||
1110 	    (i != argc && opt_d == TRUE) || (flags & DCMD_ADDRSPEC))
1111 		return (DCMD_USAGE);
1112 
1113 	if (mdb.m_depth != 1) {
1114 		mdb_warn("log may not be manipulated in this context\n");
1115 		return (DCMD_ABORT);
1116 	}
1117 
1118 	if (i != argc)
1119 		filename = argv[i].a_un.a_str;
1120 
1121 	/*
1122 	 * If no arguments were specified, print the log file name (if any)
1123 	 * and report whether the log is enabled or disabled.
1124 	 */
1125 	if (argc == 0) {
1126 		if (mdb.m_log) {
1127 			mdb_printf("%s: logging to \"%s\" is currently %s\n",
1128 			    mdb.m_pname, IOP_NAME(mdb.m_log),
1129 			    mdb.m_flags & MDB_FL_LOG ?  "enabled" : "disabled");
1130 		} else
1131 			mdb_printf("%s: no log is active\n", mdb.m_pname);
1132 		return (DCMD_OK);
1133 	}
1134 
1135 	/*
1136 	 * If the -d option was specified, pop the log i/o object off the
1137 	 * i/o stack of stdin, stdout, and stderr.
1138 	 */
1139 	if (opt_d) {
1140 		if (mdb.m_flags & MDB_FL_LOG) {
1141 			(void) mdb_iob_pop_io(mdb.m_in);
1142 			(void) mdb_iob_pop_io(mdb.m_out);
1143 			(void) mdb_iob_pop_io(mdb.m_err);
1144 			mdb.m_flags &= ~MDB_FL_LOG;
1145 		} else
1146 			mdb_warn("logging is already disabled\n");
1147 		return (DCMD_OK);
1148 	}
1149 
1150 	/*
1151 	 * The -e option is the default: (re-)enable logging by pushing
1152 	 * the log i/o object on to stdin, stdout, and stderr.  If we have
1153 	 * a previous log file, we need to pop it and close it.  If we have
1154 	 * no new log file, push the previous one back on.
1155 	 */
1156 	if (filename != NULL) {
1157 		if (mdb.m_log != NULL) {
1158 			if (mdb.m_flags & MDB_FL_LOG) {
1159 				(void) mdb_iob_pop_io(mdb.m_in);
1160 				(void) mdb_iob_pop_io(mdb.m_out);
1161 				(void) mdb_iob_pop_io(mdb.m_err);
1162 				mdb.m_flags &= ~MDB_FL_LOG;
1163 			}
1164 			mdb_io_rele(mdb.m_log);
1165 		}
1166 
1167 		mdb.m_log = mdb_fdio_create_path(NULL, filename,
1168 		    O_CREAT | O_APPEND | O_WRONLY, 0666);
1169 
1170 		if (mdb.m_log == NULL) {
1171 			mdb_warn("failed to open %s", filename);
1172 			return (DCMD_ERR);
1173 		}
1174 	}
1175 
1176 	if (mdb.m_log != NULL) {
1177 		mdb_iob_push_io(mdb.m_in, mdb_logio_create(mdb.m_log));
1178 		mdb_iob_push_io(mdb.m_out, mdb_logio_create(mdb.m_log));
1179 		mdb_iob_push_io(mdb.m_err, mdb_logio_create(mdb.m_log));
1180 
1181 		mdb_printf("%s: logging to \"%s\"\n", mdb.m_pname, filename);
1182 		mdb.m_log = mdb_io_hold(mdb.m_log);
1183 		mdb.m_flags |= MDB_FL_LOG;
1184 
1185 		return (DCMD_OK);
1186 	}
1187 
1188 	mdb_warn("no log file has been selected\n");
1189 	return (DCMD_ERR);
1190 }
1191 
1192 static int
1193 cmd_old_log(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1194 {
1195 	if (argc == 0) {
1196 		mdb_arg_t arg = { MDB_TYPE_STRING, MDB_INIT_STRING("-d") };
1197 		return (cmd_log(addr, flags, 1, &arg));
1198 	}
1199 
1200 	return (cmd_log(addr, flags, argc, argv));
1201 }
1202 #endif
1203 
1204 /*ARGSUSED*/
1205 static int
1206 cmd_load(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1207 {
1208 	int i, mode = MDB_MOD_LOCAL;
1209 
1210 	i = mdb_getopts(argc, argv,
1211 #ifdef _KMDB
1212 	    'd', MDB_OPT_SETBITS, MDB_MOD_DEFER, &mode,
1213 #endif
1214 	    'f', MDB_OPT_SETBITS, MDB_MOD_FORCE, &mode,
1215 	    'g', MDB_OPT_SETBITS, MDB_MOD_GLOBAL, &mode,
1216 	    's', MDB_OPT_SETBITS, MDB_MOD_SILENT, &mode,
1217 	    NULL);
1218 
1219 	argc -= i;
1220 	argv += i;
1221 
1222 	if ((flags & DCMD_ADDRSPEC) || argc != 1 ||
1223 	    argv->a_type != MDB_TYPE_STRING ||
1224 	    strchr("+-", argv->a_un.a_str[0]) != NULL)
1225 		return (DCMD_USAGE);
1226 
1227 	if (mdb_module_load(argv->a_un.a_str, mode) < 0)
1228 		return (DCMD_ERR);
1229 
1230 	return (DCMD_OK);
1231 }
1232 
1233 static void
1234 load_help(void)
1235 {
1236 	mdb_printf(
1237 #ifdef _KMDB
1238 	    "-d    defer load until next continue\n"
1239 #endif
1240 	    "-s    load module silently\n");
1241 }
1242 
1243 /*ARGSUSED*/
1244 static int
1245 cmd_unload(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1246 {
1247 	int mode = 0;
1248 	int i;
1249 
1250 	i = mdb_getopts(argc, argv,
1251 #ifdef _KMDB
1252 	    'd', MDB_OPT_SETBITS, MDB_MOD_DEFER, &mode,
1253 #endif
1254 	    NULL);
1255 
1256 	argc -= i;
1257 	argv += i;
1258 
1259 	if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
1260 		return (DCMD_USAGE);
1261 
1262 	if (mdb_module_unload(argv->a_un.a_str, mode) == -1) {
1263 		mdb_warn("failed to unload %s", argv->a_un.a_str);
1264 		return (DCMD_ERR);
1265 	}
1266 
1267 	return (DCMD_OK);
1268 }
1269 
1270 #ifdef _KMDB
1271 static void
1272 unload_help(void)
1273 {
1274 	mdb_printf(
1275 	    "-d    defer unload until next continue\n");
1276 }
1277 #endif
1278 
1279 static int
1280 cmd_dbmode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1281 {
1282 	if (argc > 1 || (argc != 0 && (flags & DCMD_ADDRSPEC)))
1283 		return (DCMD_USAGE);
1284 
1285 	if (argc != 0) {
1286 		if (argv->a_type != MDB_TYPE_STRING)
1287 			return (DCMD_USAGE);
1288 		if ((addr = mdb_dstr2mode(argv->a_un.a_str)) != MDB_DBG_HELP)
1289 			mdb_dmode(addr);
1290 	} else if (flags & DCMD_ADDRSPEC)
1291 		mdb_dmode(addr);
1292 
1293 	mdb_printf("debugging mode = 0x%04x\n", mdb.m_debug);
1294 	return (DCMD_OK);
1295 }
1296 
1297 /*ARGSUSED*/
1298 static int
1299 cmd_version(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1300 {
1301 #ifdef DEBUG
1302 	mdb_printf("\r%s (DEBUG)\n", mdb_conf_version());
1303 #else
1304 	mdb_printf("\r%s\n", mdb_conf_version());
1305 #endif
1306 	return (DCMD_OK);
1307 }
1308 
1309 /*ARGSUSED*/
1310 static int
1311 cmd_algol(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1312 {
1313 	if (mdb.m_flags & MDB_FL_ADB)
1314 		mdb_printf("No algol 68 here\n");
1315 	else
1316 		mdb_printf("No adb here\n");
1317 	return (DCMD_OK);
1318 }
1319 
1320 /*ARGSUSED*/
1321 static int
1322 cmd_obey(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1323 {
1324 	if (mdb.m_flags & MDB_FL_ADB)
1325 		mdb_printf("CHAPTER 1\n");
1326 	else
1327 		mdb_printf("No Language H here\n");
1328 	return (DCMD_OK);
1329 }
1330 
1331 /*ARGSUSED*/
1332 static int
1333 print_global(void *data, const GElf_Sym *sym, const char *name,
1334     const mdb_syminfo_t *sip, const char *obj)
1335 {
1336 	uintptr_t value;
1337 
1338 	if (mdb_tgt_vread((mdb_tgt_t *)data, &value, sizeof (value),
1339 	    (uintptr_t)sym->st_value) == sizeof (value))
1340 		mdb_printf("%s(%llr):\t%lr\n", name, sym->st_value, value);
1341 	else
1342 		mdb_printf("%s(%llr):\t?\n", name, sym->st_value);
1343 
1344 	return (0);
1345 }
1346 
1347 /*ARGSUSED*/
1348 static int
1349 cmd_globals(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1350 {
1351 	if (argc != 0)
1352 		return (DCMD_USAGE);
1353 
1354 	(void) mdb_tgt_symbol_iter(mdb.m_target, MDB_TGT_OBJ_EVERY,
1355 	    MDB_TGT_SYMTAB, MDB_TGT_BIND_GLOBAL | MDB_TGT_TYPE_OBJECT |
1356 	    MDB_TGT_TYPE_FUNC, print_global, mdb.m_target);
1357 
1358 	return (0);
1359 }
1360 
1361 /*ARGSUSED*/
1362 static int
1363 cmd_eval(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1364 {
1365 	if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
1366 		return (DCMD_USAGE);
1367 
1368 	if (mdb_eval(argv->a_un.a_str) == -1)
1369 		return (DCMD_ABORT);
1370 
1371 	return (DCMD_OK);
1372 }
1373 
1374 /*ARGSUSED*/
1375 static int
1376 print_file(void *data, const GElf_Sym *sym, const char *name,
1377     const mdb_syminfo_t *sip, const char *obj)
1378 {
1379 	int i = *((int *)data);
1380 
1381 	mdb_printf("%d\t%s\n", i++, name);
1382 	*((int *)data) = i;
1383 	return (0);
1384 }
1385 
1386 /*ARGSUSED*/
1387 static int
1388 cmd_files(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1389 {
1390 	int i = 1;
1391 	const char *obj = MDB_TGT_OBJ_EVERY;
1392 
1393 	if ((flags & DCMD_ADDRSPEC) || argc > 1)
1394 		return (DCMD_USAGE);
1395 
1396 	if (argc == 1) {
1397 		if (argv->a_type != MDB_TYPE_STRING)
1398 			return (DCMD_USAGE);
1399 
1400 		obj = argv->a_un.a_str;
1401 	}
1402 
1403 	(void) mdb_tgt_symbol_iter(mdb.m_target, obj, MDB_TGT_SYMTAB,
1404 	    MDB_TGT_BIND_ANY | MDB_TGT_TYPE_FILE, print_file, &i);
1405 
1406 	return (DCMD_OK);
1407 }
1408 
1409 static const char *
1410 map_name(const mdb_map_t *map, const char *name)
1411 {
1412 	if (map->map_flags & MDB_TGT_MAP_HEAP)
1413 		return ("[ heap ]");
1414 	if (name != NULL && name[0] != 0)
1415 		return (name);
1416 
1417 	if (map->map_flags & MDB_TGT_MAP_SHMEM)
1418 		return ("[ shmem ]");
1419 	if (map->map_flags & MDB_TGT_MAP_STACK)
1420 		return ("[ stack ]");
1421 	if (map->map_flags & MDB_TGT_MAP_ANON)
1422 		return ("[ anon ]");
1423 	if (map->map_name != NULL)
1424 		return (map->map_name);
1425 	return ("[ unknown ]");
1426 }
1427 
1428 /*ARGSUSED*/
1429 static int
1430 print_map(void *ignored, const mdb_map_t *map, const char *name)
1431 {
1432 	name = map_name(map, name);
1433 
1434 	mdb_printf("%?p %?p %?lx %s\n", map->map_base,
1435 	    map->map_base + map->map_size, map->map_size, name);
1436 	return (0);
1437 }
1438 
1439 static int
1440 cmd_mappings(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1441 {
1442 	const mdb_map_t *m;
1443 
1444 	if (argc > 1 || (argc != 0 && (flags & DCMD_ADDRSPEC)))
1445 		return (DCMD_USAGE);
1446 
1447 	mdb_printf("%<u>%?s %?s %?s %s%</u>\n",
1448 	    "BASE", "LIMIT", "SIZE", "NAME");
1449 
1450 	if (flags & DCMD_ADDRSPEC) {
1451 		if ((m = mdb_tgt_addr_to_map(mdb.m_target, addr)) == NULL)
1452 			mdb_warn("failed to obtain mapping");
1453 		else
1454 			(void) print_map(NULL, m, NULL);
1455 
1456 	} else if (argc != 0) {
1457 		if (argv->a_type == MDB_TYPE_STRING)
1458 			m = mdb_tgt_name_to_map(mdb.m_target, argv->a_un.a_str);
1459 		else
1460 			m = mdb_tgt_addr_to_map(mdb.m_target, argv->a_un.a_val);
1461 
1462 		if (m == NULL)
1463 			mdb_warn("failed to obtain mapping");
1464 		else
1465 			(void) print_map(NULL, m, NULL);
1466 
1467 	} else if (mdb_tgt_mapping_iter(mdb.m_target, print_map, NULL) == -1)
1468 		mdb_warn("failed to iterate over mappings");
1469 
1470 	return (DCMD_OK);
1471 }
1472 
1473 static int
1474 whatis_map_callback(void *wp, const mdb_map_t *map, const char *name)
1475 {
1476 	mdb_whatis_t *w = wp;
1477 	uintptr_t cur;
1478 
1479 	name = map_name(map, name);
1480 
1481 	while (mdb_whatis_match(w, map->map_base, map->map_size, &cur))
1482 		mdb_whatis_report_address(w, cur, "in %s [%p,%p)\n",
1483 		    name, map->map_base, map->map_base + map->map_size);
1484 
1485 	return (0);
1486 }
1487 
1488 /*ARGSUSED*/
1489 int
1490 whatis_run_mappings(mdb_whatis_t *w, void *ignored)
1491 {
1492 	(void) mdb_tgt_mapping_iter(mdb.m_target, whatis_map_callback, w);
1493 	return (0);
1494 }
1495 
1496 /*ARGSUSED*/
1497 static int
1498 objects_printversion(void *ignored, const mdb_map_t *map, const char *name)
1499 {
1500 	ctf_file_t *ctfp;
1501 	const char *version;
1502 
1503 	ctfp = mdb_tgt_name_to_ctf(mdb.m_target, name);
1504 	if (ctfp == NULL || (version = ctf_label_topmost(ctfp)) == NULL)
1505 		version = "Unknown";
1506 
1507 	mdb_printf("%-28s %s\n", name, version);
1508 	return (0);
1509 }
1510 
1511 /*ARGSUSED*/
1512 static int
1513 cmd_objects(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1514 {
1515 	uint_t opt_v = FALSE;
1516 	mdb_tgt_map_f *cb;
1517 
1518 	if ((flags & DCMD_ADDRSPEC) || mdb_getopts(argc, argv,
1519 	    'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
1520 		return (DCMD_USAGE);
1521 
1522 	if (opt_v) {
1523 		cb = objects_printversion;
1524 		mdb_printf("%<u>%-28s %s%</u>\n", "NAME", "VERSION");
1525 	} else {
1526 		cb = print_map;
1527 		mdb_printf("%<u>%?s %?s %?s %s%</u>\n",
1528 		    "BASE", "LIMIT", "SIZE", "NAME");
1529 	}
1530 
1531 	if (mdb_tgt_object_iter(mdb.m_target, cb, NULL) == -1) {
1532 		mdb_warn("failed to iterate over objects");
1533 		return (DCMD_ERR);
1534 	}
1535 
1536 	return (DCMD_OK);
1537 }
1538 
1539 /*ARGSUSED*/
1540 static int
1541 showrev_addversion(void *vers_nv, const mdb_map_t *ignored, const char *object)
1542 {
1543 	ctf_file_t *ctfp;
1544 	const char *version = NULL;
1545 	char *objname;
1546 
1547 	objname = mdb_alloc(strlen(object) + 1, UM_SLEEP | UM_GC);
1548 	(void) strcpy(objname, object);
1549 
1550 	if ((ctfp = mdb_tgt_name_to_ctf(mdb.m_target, objname)) != NULL)
1551 		version = ctf_label_topmost(ctfp);
1552 
1553 	/*
1554 	 * Not all objects have CTF and label data, so set version to "Unknown".
1555 	 */
1556 	if (version == NULL)
1557 		version = "Unknown";
1558 
1559 	/*
1560 	 * The hash table implementation in OVERLOAD mode limits the version
1561 	 * name to 31 characters because we cannot specify an external name.
1562 	 * The full version name is available via the ::objects dcmd if needed.
1563 	 */
1564 	(void) mdb_nv_insert(vers_nv, version, NULL, (uintptr_t)objname,
1565 	    MDB_NV_OVERLOAD);
1566 
1567 	return (0);
1568 }
1569 
1570 static int
1571 showrev_ispatch(const char *s)
1572 {
1573 	if (s == NULL)
1574 		return (0);
1575 
1576 	if (*s == 'T')
1577 		s++; /* skip T for T-patch */
1578 
1579 	for (; *s != '\0'; s++) {
1580 		if ((*s < '0' || *s > '9') && *s != '-')
1581 			return (0);
1582 	}
1583 
1584 	return (1);
1585 }
1586 
1587 /*ARGSUSED*/
1588 static int
1589 showrev_printobject(mdb_var_t *v, void *ignored)
1590 {
1591 	mdb_printf("%s ", MDB_NV_COOKIE(v));
1592 	return (0);
1593 }
1594 
1595 static int
1596 showrev_printversion(mdb_var_t *v, void *showall)
1597 {
1598 	const char *version = mdb_nv_get_name(v);
1599 	int patch;
1600 
1601 	patch = showrev_ispatch(version);
1602 	if (patch || (uintptr_t)showall) {
1603 		mdb_printf("%s: %s  Objects: ",
1604 		    (patch ? "Patch" : "Version"), version);
1605 		(void) mdb_inc_indent(2);
1606 
1607 		mdb_nv_defn_iter(v, showrev_printobject, NULL);
1608 
1609 		(void) mdb_dec_indent(2);
1610 		mdb_printf("\n");
1611 	}
1612 
1613 	return (0);
1614 }
1615 
1616 /*
1617  * Display version information for each object in the system.
1618  * Print information about patches only, unless showall is TRUE.
1619  */
1620 static int
1621 showrev_objectversions(int showall)
1622 {
1623 	mdb_nv_t vers_nv;
1624 
1625 	(void) mdb_nv_create(&vers_nv, UM_SLEEP | UM_GC);
1626 	if (mdb_tgt_object_iter(mdb.m_target, showrev_addversion,
1627 	    &vers_nv) == -1) {
1628 		mdb_warn("failed to iterate over objects");
1629 		return (DCMD_ERR);
1630 	}
1631 
1632 	mdb_nv_sort_iter(&vers_nv, showrev_printversion,
1633 	    (void *)(uintptr_t)showall, UM_SLEEP | UM_GC);
1634 	return (DCMD_OK);
1635 }
1636 
1637 /*
1638  * Display information similar to what showrev(1M) displays when invoked
1639  * with no arguments.
1640  */
1641 static int
1642 showrev_sysinfo(void)
1643 {
1644 	const char *s;
1645 	int rc;
1646 	struct utsname u;
1647 
1648 	if ((rc = mdb_tgt_uname(mdb.m_target, &u)) != -1) {
1649 		mdb_printf("Hostname: %s\n", u.nodename);
1650 		mdb_printf("Release: %s\n", u.release);
1651 		mdb_printf("Kernel architecture: %s\n", u.machine);
1652 	}
1653 
1654 	/*
1655 	 * Match the order of the showrev(1M) output and put "Application
1656 	 * architecture" before "Kernel version"
1657 	 */
1658 	if ((s = mdb_tgt_isa(mdb.m_target)) != NULL)
1659 		mdb_printf("Application architecture: %s\n", s);
1660 
1661 	if (rc != -1)
1662 		mdb_printf("Kernel version: %s %s %s %s\n",
1663 		    u.sysname, u.release, u.machine, u.version);
1664 
1665 	if ((s = mdb_tgt_platform(mdb.m_target)) != NULL)
1666 		mdb_printf("Platform: %s\n", s);
1667 
1668 	return (DCMD_OK);
1669 }
1670 
1671 /*ARGSUSED*/
1672 static int
1673 cmd_showrev(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1674 {
1675 	uint_t opt_p = FALSE, opt_v = FALSE;
1676 
1677 	if ((flags & DCMD_ADDRSPEC) || mdb_getopts(argc, argv,
1678 	    'p', MDB_OPT_SETBITS, TRUE, &opt_p,
1679 	    'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
1680 		return (DCMD_USAGE);
1681 
1682 	if (opt_p || opt_v)
1683 		return (showrev_objectversions(opt_v));
1684 	else
1685 		return (showrev_sysinfo());
1686 }
1687 
1688 #ifdef __sparc
1689 static void
1690 findsym_output(uintptr_t *symlist, uintptr_t value, uintptr_t location)
1691 {
1692 	uintptr_t	*symbolp;
1693 
1694 	for (symbolp = symlist; *symbolp; symbolp++)
1695 		if (value == *symbolp)
1696 			mdb_printf("found %a at %a\n", value, location);
1697 }
1698 
1699 /*ARGSUSED*/
1700 static int
1701 findsym_cb(void *data, const GElf_Sym *sym, const char *name,
1702     const mdb_syminfo_t *sip, const char *obj)
1703 {
1704 	uint32_t	*text;
1705 	int		len;
1706 	int		i;
1707 	int		j;
1708 	uint8_t		rd;
1709 	uintptr_t	value;
1710 	int32_t		imm13;
1711 	uint8_t		op;
1712 	uint8_t		op3;
1713 	uintptr_t	*symlist = data;
1714 	size_t		size = sym->st_size;
1715 
1716 	/*
1717 	 * if the size of the symbol is 0, then this symbol must be for an
1718 	 * alternate entry point or just some global label. We will,
1719 	 * therefore, get back to the text that follows this symbol in
1720 	 * some other symbol
1721 	 */
1722 	if (size == 0)
1723 		return (0);
1724 
1725 	if (sym->st_shndx == SHN_UNDEF)
1726 		return (0);
1727 
1728 	text = alloca(size);
1729 
1730 	if (mdb_vread(text, size, sym->st_value) == -1) {
1731 		mdb_warn("failed to read text for %s", name);
1732 		return (0);
1733 	}
1734 
1735 	len = size / 4;
1736 	for (i = 0; i < len; i++) {
1737 		if (!IS_SETHI(text[i]))
1738 			continue;
1739 
1740 		rd = RD(text[i]);
1741 		value = IMM22(text[i]) << 10;
1742 
1743 		/*
1744 		 * see if we already have a match with just the sethi
1745 		 */
1746 		findsym_output(symlist, value, sym->st_value + i * 4);
1747 
1748 		/*
1749 		 * search from the sethi on until we hit a relevant instr
1750 		 */
1751 		for (j = i + 1; j < len; j++) {
1752 			if ((op = OP(text[j])) & OP_ARITH_MEM_MASK) {
1753 				op3 = OP3(text[j]);
1754 
1755 				if (RS1(text[j]) != rd)
1756 					goto instr_end;
1757 
1758 				/*
1759 				 * This is a simple tool; we only deal
1760 				 * with operations which take immediates
1761 				 */
1762 				if (I(text[j]) == 0)
1763 					goto instr_end;
1764 
1765 				/*
1766 				 * sign extend the immediate value
1767 				 */
1768 				imm13 = IMM13(text[j]);
1769 				imm13 <<= 19;
1770 				imm13 >>= 19;
1771 
1772 				if (op == OP_ARITH) {
1773 					/* arithmetic operations */
1774 					if (op3 & OP3_COMPLEX_MASK)
1775 						goto instr_end;
1776 
1777 					switch (op3 & ~OP3_CC_MASK) {
1778 					case OP3_OR:
1779 						value |= imm13;
1780 						break;
1781 					case OP3_ADD:
1782 						value += imm13;
1783 						break;
1784 					case OP3_XOR:
1785 						value ^= imm13;
1786 						break;
1787 					default:
1788 						goto instr_end;
1789 					}
1790 				} else {
1791 					/* loads and stores */
1792 					/* op3 == OP_MEM */
1793 
1794 					value += imm13;
1795 				}
1796 
1797 				findsym_output(symlist, value,
1798 				    sym->st_value + j * 4);
1799 instr_end:
1800 				/*
1801 				 * if we're clobbering rd, break
1802 				 */
1803 				if (RD(text[j]) == rd)
1804 					break;
1805 			} else if (IS_SETHI(text[j])) {
1806 				if (RD(text[j]) == rd)
1807 					break;
1808 			} else if (OP(text[j]) == 1) {
1809 				/*
1810 				 * see if a call clobbers an %o or %g
1811 				 */
1812 				if (rd <= R_O7)
1813 					break;
1814 			}
1815 		}
1816 	}
1817 
1818 	return (0);
1819 }
1820 
1821 static int
1822 cmd_findsym(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1823 {
1824 	uintptr_t *symlist;
1825 	uint_t optg = FALSE;
1826 	uint_t type;
1827 	int len, i;
1828 
1829 	i = mdb_getopts(argc, argv, 'g', MDB_OPT_SETBITS, TRUE, &optg, NULL);
1830 
1831 	argc -= i;
1832 	argv += i;
1833 
1834 	len = argc + ((flags & DCMD_ADDRSPEC) ? 1 : 0) + 1;
1835 
1836 	if (len <= 1)
1837 		return (DCMD_USAGE);
1838 
1839 	/*
1840 	 * Set up a NULL-terminated symbol list, and then iterate over the
1841 	 * symbol table, scanning each function for references to these symbols.
1842 	 */
1843 	symlist = mdb_alloc(len * sizeof (uintptr_t), UM_SLEEP | UM_GC);
1844 	len = 0;
1845 
1846 	for (i = 0; i < argc; i++, argv++) {
1847 		const char *str = argv->a_un.a_str;
1848 		uintptr_t value;
1849 		GElf_Sym sym;
1850 
1851 		if (argv->a_type == MDB_TYPE_STRING) {
1852 			if (strchr("+-", str[0]) != NULL)
1853 				return (DCMD_USAGE);
1854 			else if (str[0] >= '0' && str[0] <= '9')
1855 				value = mdb_strtoull(str);
1856 			else if (mdb_lookup_by_name(str, &sym) != 0) {
1857 				mdb_warn("symbol '%s' not found", str);
1858 				return (DCMD_USAGE);
1859 			} else
1860 				value = sym.st_value;
1861 		} else
1862 			value = argv[i].a_un.a_val;
1863 
1864 		if (value != NULL)
1865 			symlist[len++] = value;
1866 	}
1867 
1868 	if (flags & DCMD_ADDRSPEC)
1869 		symlist[len++] = addr;
1870 
1871 	symlist[len] = NULL;
1872 
1873 	if (optg)
1874 		type = MDB_TGT_BIND_GLOBAL | MDB_TGT_TYPE_FUNC;
1875 	else
1876 		type = MDB_TGT_BIND_ANY | MDB_TGT_TYPE_FUNC;
1877 
1878 	if (mdb_tgt_symbol_iter(mdb.m_target, MDB_TGT_OBJ_EVERY,
1879 	    MDB_TGT_SYMTAB, type, findsym_cb, symlist) == -1) {
1880 		mdb_warn("failed to iterate over symbol table");
1881 		return (DCMD_ERR);
1882 	}
1883 
1884 	return (DCMD_OK);
1885 }
1886 #endif /* __sparc */
1887 
1888 static int
1889 dis_str2addr(const char *s, uintptr_t *addr)
1890 {
1891 	GElf_Sym sym;
1892 
1893 	if (s[0] >= '0' && s[0] <= '9') {
1894 		*addr = (uintptr_t)mdb_strtoull(s);
1895 		return (0);
1896 	}
1897 
1898 	if (mdb_tgt_lookup_by_name(mdb.m_target,
1899 	    MDB_TGT_OBJ_EVERY, s, &sym, NULL) == -1) {
1900 		mdb_warn("symbol '%s' not found\n", s);
1901 		return (-1);
1902 	}
1903 
1904 	*addr = (uintptr_t)sym.st_value;
1905 	return (0);
1906 }
1907 
1908 static int
1909 cmd_dis(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1910 {
1911 	mdb_tgt_t *tgt = mdb.m_target;
1912 	mdb_disasm_t *dis = mdb.m_disasm;
1913 
1914 	uintptr_t oaddr, naddr;
1915 	mdb_tgt_as_t as;
1916 	mdb_tgt_status_t st;
1917 	char buf[BUFSIZ];
1918 	GElf_Sym sym;
1919 	int i;
1920 
1921 	uint_t opt_f = FALSE;		/* File-mode off by default */
1922 	uint_t opt_w = FALSE;		/* Window mode off by default */
1923 	uint_t opt_a = FALSE;		/* Raw-address mode off by default */
1924 	uint_t opt_b = FALSE;		/* Address & symbols off by default */
1925 	uintptr_t n = -1UL;		/* Length of window in instructions */
1926 	uintptr_t eaddr = 0;		/* Ending address; 0 if limited by n */
1927 
1928 	i = mdb_getopts(argc, argv,
1929 	    'f', MDB_OPT_SETBITS, TRUE, &opt_f,
1930 	    'w', MDB_OPT_SETBITS, TRUE, &opt_w,
1931 	    'a', MDB_OPT_SETBITS, TRUE, &opt_a,
1932 	    'b', MDB_OPT_SETBITS, TRUE, &opt_b,
1933 	    'n', MDB_OPT_UINTPTR, &n, NULL);
1934 
1935 	/*
1936 	 * Disgusting argument post-processing ... basically the idea is to get
1937 	 * the target address into addr, which we do by using the specified
1938 	 * expression value, looking up a string as a symbol name, or by
1939 	 * using the address specified as dot.
1940 	 */
1941 	if (i != argc) {
1942 		if (argc != 0 && (argc - i) == 1) {
1943 			if (argv[i].a_type == MDB_TYPE_STRING) {
1944 				if (argv[i].a_un.a_str[0] == '-')
1945 					return (DCMD_USAGE);
1946 
1947 				if (dis_str2addr(argv[i].a_un.a_str, &addr))
1948 					return (DCMD_ERR);
1949 			} else
1950 				addr = argv[i].a_un.a_val;
1951 		} else
1952 			return (DCMD_USAGE);
1953 	}
1954 
1955 	/*
1956 	 * If we're not in window mode yet, and some type of arguments were
1957 	 * specified, see if the address corresponds nicely to a function.
1958 	 * If not, turn on window mode; otherwise disassemble the function.
1959 	 */
1960 	if (opt_w == FALSE && (argc != i || (flags & DCMD_ADDRSPEC))) {
1961 		if (mdb_tgt_lookup_by_addr(tgt, addr,
1962 		    MDB_TGT_SYM_EXACT, buf, sizeof (buf), &sym, NULL) == 0 &&
1963 		    GELF_ST_TYPE(sym.st_info) == STT_FUNC) {
1964 			/*
1965 			 * If the symbol has a size then set our end address to
1966 			 * be the end of the function symbol we just located.
1967 			 */
1968 			if (sym.st_size != 0)
1969 				eaddr = addr + (uintptr_t)sym.st_size;
1970 		} else
1971 			opt_w = TRUE;
1972 	}
1973 
1974 	/*
1975 	 * Window-mode doesn't make sense in a loop.
1976 	 */
1977 	if (flags & DCMD_LOOP)
1978 		opt_w = FALSE;
1979 
1980 	/*
1981 	 * If -n was explicit, limit output to n instructions;
1982 	 * otherwise set n to some reasonable default
1983 	 */
1984 	if (n != -1UL)
1985 		eaddr = 0;
1986 	else
1987 		n = 10;
1988 
1989 	/*
1990 	 * If the state is IDLE (i.e. no address space), turn on -f.
1991 	 */
1992 	if (mdb_tgt_status(tgt, &st) == 0 && st.st_state == MDB_TGT_IDLE)
1993 		opt_f = TRUE;
1994 
1995 	if (opt_f)
1996 		as = MDB_TGT_AS_FILE;
1997 	else
1998 		as = MDB_TGT_AS_VIRT;
1999 
2000 	if (opt_w == FALSE) {
2001 		n++;
2002 		while ((eaddr == 0 && n-- != 0) || (addr < eaddr)) {
2003 			naddr = mdb_dis_ins2str(dis, tgt, as,
2004 			    buf, sizeof (buf), addr);
2005 			if (naddr == addr)
2006 				return (DCMD_ERR);
2007 			if (opt_a)
2008 				mdb_printf("%-#32p%8T%s\n", addr, buf);
2009 			else if (opt_b)
2010 				mdb_printf("%-#10p%-#32a%8T%s\n",
2011 				    addr, addr, buf);
2012 			else
2013 				mdb_printf("%-#32a%8T%s\n", addr, buf);
2014 			addr = naddr;
2015 		}
2016 
2017 	} else {
2018 #ifdef __sparc
2019 		if (addr & 0x3) {
2020 			mdb_warn("address is not properly aligned\n");
2021 			return (DCMD_ERR);
2022 		}
2023 #endif
2024 
2025 		for (oaddr = mdb_dis_previns(dis, tgt, as, addr, n);
2026 		    oaddr < addr; oaddr = naddr) {
2027 			naddr = mdb_dis_ins2str(dis, tgt, as,
2028 			    buf, sizeof (buf), oaddr);
2029 			if (naddr == oaddr)
2030 				return (DCMD_ERR);
2031 			if (opt_a)
2032 				mdb_printf("%-#32p%8T%s\n", oaddr, buf);
2033 			else if (opt_b)
2034 				mdb_printf("%-#10p%-#32a%8T%s\n",
2035 				    oaddr, oaddr, buf);
2036 			else
2037 				mdb_printf("%-#32a%8T%s\n", oaddr, buf);
2038 		}
2039 
2040 		if ((naddr = mdb_dis_ins2str(dis, tgt, as,
2041 		    buf, sizeof (buf), addr)) == addr)
2042 			return (DCMD_ERR);
2043 
2044 		mdb_printf("%<b>");
2045 		mdb_flush();
2046 		if (opt_a)
2047 			mdb_printf("%-#32p%8T%s%", addr, buf);
2048 		else if (opt_b)
2049 			mdb_printf("%-#10p%-#32a%8T%s", addr, addr, buf);
2050 		else
2051 			mdb_printf("%-#32a%8T%s%", addr, buf);
2052 		mdb_printf("%</b>\n");
2053 
2054 		for (addr = naddr; n-- != 0; addr = naddr) {
2055 			naddr = mdb_dis_ins2str(dis, tgt, as,
2056 			    buf, sizeof (buf), addr);
2057 			if (naddr == addr)
2058 				return (DCMD_ERR);
2059 			if (opt_a)
2060 				mdb_printf("%-#32p%8T%s\n", addr, buf);
2061 			else if (opt_b)
2062 				mdb_printf("%-#10p%-#32a%8T%s\n",
2063 				    addr, addr, buf);
2064 			else
2065 				mdb_printf("%-#32a%8T%s\n", addr, buf);
2066 		}
2067 	}
2068 
2069 	mdb_set_dot(addr);
2070 	return (DCMD_OK);
2071 }
2072 
2073 /*ARGSUSED*/
2074 static int
2075 walk_step(uintptr_t addr, const void *data, void *private)
2076 {
2077 	mdb_printf("%lr\n", addr);
2078 	return (WALK_NEXT);
2079 }
2080 
2081 static int
2082 cmd_walk(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2083 {
2084 	int status;
2085 
2086 	if (argc < 1 || argc > 2 || argv[0].a_type != MDB_TYPE_STRING ||
2087 	    argv[argc - 1].a_type != MDB_TYPE_STRING)
2088 		return (DCMD_USAGE);
2089 
2090 	if (argc > 1) {
2091 		const char *name = argv[1].a_un.a_str;
2092 		mdb_var_t *v = mdb_nv_lookup(&mdb.m_nv, name);
2093 		const char *p;
2094 
2095 		if (v != NULL && (v->v_flags & MDB_NV_RDONLY) != 0) {
2096 			mdb_warn("variable %s is read-only\n", name);
2097 			return (DCMD_ABORT);
2098 		}
2099 
2100 		if (v == NULL && (p = strbadid(name)) != NULL) {
2101 			mdb_warn("'%c' may not be used in a variable "
2102 			    "name\n", *p);
2103 			return (DCMD_ABORT);
2104 		}
2105 
2106 		if (v == NULL && (v = mdb_nv_insert(&mdb.m_nv,
2107 		    name, NULL, 0, 0)) == NULL)
2108 			return (DCMD_ERR);
2109 
2110 		/*
2111 		 * If there already exists a vcb for this variable, we may be
2112 		 * calling ::walk in a loop.  We only create a vcb for this
2113 		 * variable on the first invocation.
2114 		 */
2115 		if (mdb_vcb_find(v, mdb.m_frame) == NULL)
2116 			mdb_vcb_insert(mdb_vcb_create(v), mdb.m_frame);
2117 	}
2118 
2119 	if (flags & DCMD_ADDRSPEC)
2120 		status = mdb_pwalk(argv->a_un.a_str, walk_step, NULL, addr);
2121 	else
2122 		status = mdb_walk(argv->a_un.a_str, walk_step, NULL);
2123 
2124 	if (status == -1) {
2125 		mdb_warn("failed to perform walk");
2126 		return (DCMD_ERR);
2127 	}
2128 
2129 	return (DCMD_OK);
2130 }
2131 
2132 static ssize_t
2133 mdb_partial_xread(void *buf, size_t nbytes, uintptr_t addr, void *arg)
2134 {
2135 	ssize_t (*fp)(mdb_tgt_t *, const void *, size_t, uintptr_t) =
2136 	    (ssize_t (*)(mdb_tgt_t *, const void *, size_t, uintptr_t))arg;
2137 
2138 	return (fp(mdb.m_target, buf, nbytes, addr));
2139 }
2140 
2141 /* ARGSUSED3 */
2142 static ssize_t
2143 mdb_partial_pread(void *buf, size_t nbytes, physaddr_t addr, void *arg)
2144 {
2145 	return (mdb_tgt_pread(mdb.m_target, buf, nbytes, addr));
2146 }
2147 
2148 
2149 static int
2150 cmd_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2151 {
2152 	uint_t dflags =
2153 	    MDB_DUMP_ALIGN | MDB_DUMP_NEWDOT | MDB_DUMP_ASCII | MDB_DUMP_HEADER;
2154 	uint_t phys = FALSE;
2155 	uint_t file = FALSE;
2156 	uintptr_t group = 4;
2157 	uintptr_t width = 1;
2158 	mdb_tgt_status_t st;
2159 	int error;
2160 
2161 	if (mdb_getopts(argc, argv,
2162 	    'e', MDB_OPT_SETBITS, MDB_DUMP_ENDIAN, &dflags,
2163 	    'f', MDB_OPT_SETBITS, TRUE, &file,
2164 	    'g', MDB_OPT_UINTPTR, &group,
2165 	    'p', MDB_OPT_SETBITS, TRUE, &phys,
2166 	    'q', MDB_OPT_CLRBITS, MDB_DUMP_ASCII, &dflags,
2167 	    'r', MDB_OPT_SETBITS, MDB_DUMP_RELATIVE, &dflags,
2168 	    's', MDB_OPT_SETBITS, MDB_DUMP_SQUISH, &dflags,
2169 	    't', MDB_OPT_SETBITS, MDB_DUMP_TRIM, &dflags,
2170 	    'u', MDB_OPT_CLRBITS, MDB_DUMP_ALIGN, &dflags,
2171 	    'v', MDB_OPT_SETBITS, MDB_DUMP_PEDANT, &dflags,
2172 	    'w', MDB_OPT_UINTPTR, &width, NULL) != argc)
2173 		return (DCMD_USAGE);
2174 
2175 	if ((phys && file) ||
2176 	    (width == 0) || (width > 0x10) ||
2177 	    (group == 0) || (group > 0x100))
2178 		return (DCMD_USAGE);
2179 
2180 	/*
2181 	 * If neither -f nor -p were specified and the state is IDLE (i.e. no
2182 	 * address space), turn on -p.  This is so we can read large files.
2183 	 */
2184 	if (phys == FALSE && file == FALSE && mdb_tgt_status(mdb.m_target,
2185 	    &st) == 0 && st.st_state == MDB_TGT_IDLE)
2186 		phys = TRUE;
2187 
2188 	dflags |= MDB_DUMP_GROUP(group) | MDB_DUMP_WIDTH(width);
2189 	if (phys)
2190 		error = mdb_dump64(mdb_get_dot(), mdb.m_dcount, dflags,
2191 		    mdb_partial_pread, NULL);
2192 	else if (file)
2193 		error = mdb_dumpptr(addr, mdb.m_dcount, dflags,
2194 		    mdb_partial_xread, (void *)mdb_tgt_fread);
2195 	else
2196 		error = mdb_dumpptr(addr, mdb.m_dcount, dflags,
2197 		    mdb_partial_xread, (void *)mdb_tgt_vread);
2198 
2199 	return (((flags & DCMD_LOOP) || (error == -1)) ? DCMD_ABORT : DCMD_OK);
2200 }
2201 
2202 /*ARGSUSED*/
2203 static int
2204 cmd_echo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2205 {
2206 	if (flags & DCMD_ADDRSPEC)
2207 		return (DCMD_USAGE);
2208 
2209 	for (; argc-- != 0; argv++) {
2210 		if (argv->a_type == MDB_TYPE_STRING)
2211 			mdb_printf("%s ", argv->a_un.a_str);
2212 		else
2213 			mdb_printf("%llr ", argv->a_un.a_val);
2214 	}
2215 
2216 	mdb_printf("\n");
2217 	return (DCMD_OK);
2218 }
2219 
2220 /*ARGSUSED*/
2221 static int
2222 cmd_head(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2223 {
2224 	uint64_t cnt = 10;
2225 	const char *c;
2226 	mdb_pipe_t p;
2227 
2228 	if (!flags & DCMD_PIPE)
2229 		return (DCMD_USAGE);
2230 
2231 	if (argc == 1 || argc == 2) {
2232 		const char *num;
2233 
2234 		if (argc == 1) {
2235 			if (argv[0].a_type != MDB_TYPE_STRING ||
2236 			    *argv[0].a_un.a_str != '-')
2237 				return (DCMD_USAGE);
2238 
2239 			num = argv[0].a_un.a_str + 1;
2240 
2241 		} else {
2242 			if (argv[0].a_type != MDB_TYPE_STRING ||
2243 			    strcmp(argv[0].a_un.a_str, "-n") != 0)
2244 				return (DCMD_USAGE);
2245 
2246 			num = argv[1].a_un.a_str;
2247 		}
2248 
2249 		for (cnt = 0, c = num; *c != '\0' && isdigit(*c); c++)
2250 			cnt = cnt * 10 + (*c - '0');
2251 
2252 		if (*c != '\0')
2253 			return (DCMD_USAGE);
2254 
2255 	} else if (argc != 0) {
2256 		return (DCMD_USAGE);
2257 	}
2258 
2259 	mdb_get_pipe(&p);
2260 
2261 	if (p.pipe_data == NULL)
2262 		return (DCMD_OK);
2263 	p.pipe_len = MIN(p.pipe_len, cnt);
2264 
2265 	if (flags & DCMD_PIPE_OUT) {
2266 		mdb_set_pipe(&p);
2267 	} else {
2268 		while (p.pipe_len-- > 0)
2269 			mdb_printf("%lx\n", *p.pipe_data++);
2270 	}
2271 
2272 	return (DCMD_OK);
2273 }
2274 
2275 static void
2276 head_help(void)
2277 {
2278 	mdb_printf(
2279 	    "-n num\n or\n"
2280 	    "-num   pass only the first `num' elements in the pipe.\n"
2281 	    "\n%<b>Note:%</b> `num' is a decimal number.\n");
2282 }
2283 
2284 static int
2285 cmd_typeset(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2286 {
2287 	int add_tag = 0, del_tag = 0;
2288 	const char *p;
2289 	mdb_var_t *v;
2290 
2291 	if (argc == 0)
2292 		return (cmd_vars(addr, flags, argc, argv));
2293 
2294 	if (argv->a_type == MDB_TYPE_STRING && (argv->a_un.a_str[0] == '-' ||
2295 	    argv->a_un.a_str[0] == '+')) {
2296 		if (argv->a_un.a_str[1] != 't')
2297 			return (DCMD_USAGE);
2298 		if (argv->a_un.a_str[0] == '-')
2299 			add_tag++;
2300 		else
2301 			del_tag++;
2302 		argc--;
2303 		argv++;
2304 	}
2305 
2306 	if (!(flags & DCMD_ADDRSPEC))
2307 		addr = 0; /* set variables to zero unless explicit addr given */
2308 
2309 	for (; argc-- != 0; argv++) {
2310 		if (argv->a_type != MDB_TYPE_STRING)
2311 			continue;
2312 
2313 		if (argv->a_un.a_str[0] == '-' || argv->a_un.a_str[0] == '+') {
2314 			mdb_warn("ignored bad option -- %s\n",
2315 			    argv->a_un.a_str);
2316 			continue;
2317 		}
2318 
2319 		if ((p = strbadid(argv->a_un.a_str)) != NULL) {
2320 			mdb_warn("'%c' may not be used in a variable "
2321 			    "name\n", *p);
2322 			return (DCMD_ERR);
2323 		}
2324 
2325 		if ((v = mdb_nv_lookup(&mdb.m_nv, argv->a_un.a_str)) == NULL) {
2326 			v = mdb_nv_insert(&mdb.m_nv, argv->a_un.a_str,
2327 			    NULL, addr, 0);
2328 		} else if (flags & DCMD_ADDRSPEC)
2329 			mdb_nv_set_value(v, addr);
2330 
2331 		if (v != NULL) {
2332 			if (add_tag)
2333 				v->v_flags |= MDB_NV_TAGGED;
2334 			if (del_tag)
2335 				v->v_flags &= ~MDB_NV_TAGGED;
2336 		}
2337 	}
2338 
2339 	return (DCMD_OK);
2340 }
2341 
2342 #ifndef _KMDB
2343 /*ARGSUSED*/
2344 static int
2345 cmd_context(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2346 {
2347 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
2348 		return (DCMD_USAGE);
2349 
2350 	if (mdb_tgt_setcontext(mdb.m_target, (void *)addr) == 0)
2351 		return (DCMD_OK);
2352 
2353 	return (DCMD_ERR);
2354 }
2355 #endif
2356 
2357 /*ARGSUSED*/
2358 static int
2359 cmd_prompt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2360 {
2361 	const char *p = "";
2362 
2363 	if (argc != 0) {
2364 		if (argc > 1 || argv->a_type != MDB_TYPE_STRING)
2365 			return (DCMD_USAGE);
2366 		p = argv->a_un.a_str;
2367 	}
2368 
2369 	(void) mdb_set_prompt(p);
2370 	return (DCMD_OK);
2371 }
2372 
2373 /*ARGSUSED*/
2374 static int
2375 cmd_term(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2376 {
2377 	mdb_printf("%s\n", mdb.m_termtype);
2378 
2379 	return (DCMD_OK);
2380 }
2381 
2382 /*ARGSUSED*/
2383 static int
2384 cmd_vtop(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2385 {
2386 	physaddr_t pa;
2387 	mdb_tgt_as_t as = MDB_TGT_AS_VIRT;
2388 
2389 	if (mdb_getopts(argc, argv, 'a', MDB_OPT_UINTPTR, (uintptr_t *)&as,
2390 	    NULL) != argc)
2391 		return (DCMD_USAGE);
2392 
2393 	if (mdb_tgt_vtop(mdb.m_target, as, addr, &pa) == -1) {
2394 		mdb_warn("failed to get physical mapping");
2395 		return (DCMD_ERR);
2396 	}
2397 
2398 	if (flags & DCMD_PIPE_OUT)
2399 		mdb_printf("%llr\n", pa);
2400 	else
2401 		mdb_printf("virtual %lr mapped to physical %llr\n", addr, pa);
2402 	return (DCMD_OK);
2403 }
2404 
2405 #define	EVENTS_OPT_A	0x1	/* ::events -a (show all events) */
2406 #define	EVENTS_OPT_V	0x2	/* ::events -v (verbose display) */
2407 
2408 static const char *
2409 event_action(const mdb_tgt_spec_desc_t *sp)
2410 {
2411 	if (!(sp->spec_flags & MDB_TGT_SPEC_HIDDEN) && sp->spec_data != NULL)
2412 		return (sp->spec_data);
2413 
2414 	return ("-");
2415 }
2416 
2417 static void
2418 print_evsep(void)
2419 {
2420 	static const char dash20[] = "--------------------";
2421 	mdb_printf("----- - -- -- -- %s%s --%s\n", dash20, dash20, dash20);
2422 }
2423 
2424 /*ARGSUSED*/
2425 static int
2426 print_event(mdb_tgt_t *t, void *private, int vid, void *data)
2427 {
2428 	uint_t opts = (uint_t)(uintptr_t)private;
2429 	mdb_tgt_spec_desc_t sp;
2430 	char s1[41], s2[22];
2431 	const char *s2str;
2432 	int visible;
2433 
2434 	(void) mdb_tgt_vespec_info(t, vid, &sp, s1, sizeof (s1));
2435 	visible = !(sp.spec_flags & (MDB_TGT_SPEC_HIDDEN|MDB_TGT_SPEC_DELETED));
2436 
2437 	if ((opts & EVENTS_OPT_A) || visible) {
2438 		int encoding = (!(sp.spec_flags & MDB_TGT_SPEC_DISABLED)) |
2439 		    (!(sp.spec_flags & MDB_TGT_SPEC_MATCHED) << 1);
2440 
2441 		char ldelim = "<<(["[encoding];
2442 		char rdelim = ">>)]"[encoding];
2443 
2444 		char state = "0-+*!"[sp.spec_state];
2445 
2446 		char tflag = "T "[!(sp.spec_flags & MDB_TGT_SPEC_STICKY)];
2447 		char aflag = "d "[!(sp.spec_flags & MDB_TGT_SPEC_AUTODIS)];
2448 
2449 		if (sp.spec_flags & MDB_TGT_SPEC_TEMPORARY)
2450 			tflag = 't'; /* TEMP takes precedence over STICKY */
2451 		if (sp.spec_flags & MDB_TGT_SPEC_AUTODEL)
2452 			aflag = 'D'; /* AUTODEL takes precedence over AUTODIS */
2453 		if (sp.spec_flags & MDB_TGT_SPEC_AUTOSTOP)
2454 			aflag = 's'; /* AUTOSTOP takes precedence over both */
2455 
2456 		if (opts & EVENTS_OPT_V) {
2457 			if (sp.spec_state == MDB_TGT_SPEC_IDLE ||
2458 			    sp.spec_state == MDB_TGT_SPEC_ERROR)
2459 				s2str = mdb_strerror(sp.spec_errno);
2460 			else
2461 				s2str = "-";
2462 		} else
2463 			s2str = event_action(&sp);
2464 
2465 		if (mdb_snprintf(s2, sizeof (s2), "%s", s2str) >= sizeof (s2))
2466 			(void) strabbr(s2, sizeof (s2));
2467 
2468 		if (vid > -10 && vid < 10)
2469 			mdb_printf("%c%2d %c", ldelim, vid, rdelim);
2470 		else
2471 			mdb_printf("%c%3d%c", ldelim, vid, rdelim);
2472 
2473 		mdb_printf(" %c %c%c %2u %2u %-40s %-21s\n",
2474 		    state, tflag, aflag, sp.spec_hits, sp.spec_limit, s1, s2);
2475 
2476 		if (opts & EVENTS_OPT_V) {
2477 			mdb_printf("%-17s%s\n", "", event_action(&sp));
2478 			print_evsep();
2479 		}
2480 	}
2481 
2482 	return (0);
2483 }
2484 
2485 /*ARGSUSED*/
2486 static int
2487 cmd_events(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2488 {
2489 	uint_t opts = 0;
2490 
2491 	if ((flags & DCMD_ADDRSPEC) || mdb_getopts(argc, argv,
2492 	    'a', MDB_OPT_SETBITS, EVENTS_OPT_A, &opts,
2493 	    'v', MDB_OPT_SETBITS, EVENTS_OPT_V, &opts, NULL) != argc)
2494 		return (DCMD_USAGE);
2495 
2496 
2497 	if (opts & EVENTS_OPT_V) {
2498 		mdb_printf("   ID S TA HT LM %-40s %-21s\n%-17s%s\n",
2499 		    "Description", "Status", "", "Action");
2500 	} else {
2501 		mdb_printf("   ID S TA HT LM %-40s %-21s\n",
2502 		    "Description", "Action");
2503 	}
2504 
2505 	print_evsep();
2506 	return (mdb_tgt_vespec_iter(mdb.m_target, print_event,
2507 	    (void *)(uintptr_t)opts));
2508 }
2509 
2510 static int
2511 tgt_status(const mdb_tgt_status_t *tsp)
2512 {
2513 	const char *format;
2514 	char buf[BUFSIZ];
2515 
2516 	if (tsp->st_flags & MDB_TGT_BUSY)
2517 		return (DCMD_OK);
2518 
2519 	if (tsp->st_pc != 0) {
2520 		if (mdb_dis_ins2str(mdb.m_disasm, mdb.m_target, MDB_TGT_AS_VIRT,
2521 		    buf, sizeof (buf), tsp->st_pc) != tsp->st_pc)
2522 			format = "target stopped at:\n%-#16a%8T%s\n";
2523 		else
2524 			format = "target stopped at %a:\n";
2525 		mdb_warn(format, tsp->st_pc, buf);
2526 	}
2527 
2528 	switch (tsp->st_state) {
2529 	case MDB_TGT_IDLE:
2530 		mdb_warn("target is idle\n");
2531 		break;
2532 	case MDB_TGT_RUNNING:
2533 		if (tsp->st_flags & MDB_TGT_DSTOP)
2534 			mdb_warn("target is running, stop directive pending\n");
2535 		else
2536 			mdb_warn("target is running\n");
2537 		break;
2538 	case MDB_TGT_STOPPED:
2539 		if (tsp->st_pc == 0)
2540 			mdb_warn("target is stopped\n");
2541 		break;
2542 	case MDB_TGT_UNDEAD:
2543 		mdb_warn("target has terminated\n");
2544 		break;
2545 	case MDB_TGT_DEAD:
2546 		mdb_warn("target is a core dump\n");
2547 		break;
2548 	case MDB_TGT_LOST:
2549 		mdb_warn("target is no longer under debugger control\n");
2550 		break;
2551 	}
2552 
2553 	mdb_set_dot(tsp->st_pc);
2554 	return (DCMD_OK);
2555 }
2556 
2557 /*
2558  * mdb continue/step commands take an optional signal argument, but the
2559  * corresponding kmdb versions don't.
2560  */
2561 #ifdef _KMDB
2562 #define	CONT_MAXARGS	0	/* no optional SIG argument */
2563 #else
2564 #define	CONT_MAXARGS	1
2565 #endif
2566 
2567 /*ARGSUSED*/
2568 static int
2569 cmd_cont_common(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv,
2570     int (*t_cont)(mdb_tgt_t *, mdb_tgt_status_t *), const char *name)
2571 {
2572 	mdb_tgt_t *t = mdb.m_target;
2573 	mdb_tgt_status_t st;
2574 	int sig = 0;
2575 
2576 	if ((flags & DCMD_ADDRSPEC) || argc > CONT_MAXARGS)
2577 		return (DCMD_USAGE);
2578 
2579 	if (argc > 0) {
2580 		if (argv->a_type == MDB_TYPE_STRING) {
2581 			if (proc_str2sig(argv->a_un.a_str, &sig) == -1) {
2582 				mdb_warn("invalid signal name -- %s\n",
2583 				    argv->a_un.a_str);
2584 				return (DCMD_USAGE);
2585 			}
2586 		} else
2587 			sig = (int)(intmax_t)argv->a_un.a_val;
2588 	}
2589 
2590 	(void) mdb_tgt_status(t, &st);
2591 
2592 	if (st.st_state == MDB_TGT_IDLE && mdb_tgt_run(t, 0, NULL) == -1) {
2593 		if (errno != EMDB_TGT)
2594 			mdb_warn("failed to create new target");
2595 		return (DCMD_ERR);
2596 	}
2597 
2598 	if (sig != 0 && mdb_tgt_signal(t, sig) == -1) {
2599 		mdb_warn("failed to post signal %d", sig);
2600 		return (DCMD_ERR);
2601 	}
2602 
2603 	if (st.st_state == MDB_TGT_IDLE && t_cont == &mdb_tgt_step) {
2604 		(void) mdb_tgt_status(t, &st);
2605 		return (tgt_status(&st));
2606 	}
2607 
2608 	if (t_cont(t, &st) == -1) {
2609 		if (errno != EMDB_TGT)
2610 			mdb_warn("failed to %s target", name);
2611 		return (DCMD_ERR);
2612 	}
2613 
2614 	return (tgt_status(&st));
2615 }
2616 
2617 static int
2618 cmd_step(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2619 {
2620 	int (*func)(mdb_tgt_t *, mdb_tgt_status_t *) = &mdb_tgt_step;
2621 	const char *name = "single-step";
2622 
2623 	if (argc > 0 && argv->a_type == MDB_TYPE_STRING) {
2624 		if (strcmp(argv->a_un.a_str, "out") == 0) {
2625 			func = &mdb_tgt_step_out;
2626 			name = "step (out)";
2627 			argv++;
2628 			argc--;
2629 		} else if (strcmp(argv->a_un.a_str, "branch") == 0) {
2630 			func = &mdb_tgt_step_branch;
2631 			name = "step (branch)";
2632 			argv++;
2633 			argc--;
2634 		} else if (strcmp(argv->a_un.a_str, "over") == 0) {
2635 			func = &mdb_tgt_next;
2636 			name = "step (over)";
2637 			argv++;
2638 			argc--;
2639 		}
2640 	}
2641 
2642 	return (cmd_cont_common(addr, flags, argc, argv, func, name));
2643 }
2644 
2645 static int
2646 cmd_step_out(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2647 {
2648 	return (cmd_cont_common(addr, flags, argc, argv,
2649 	    &mdb_tgt_step_out, "step (out)"));
2650 }
2651 
2652 static int
2653 cmd_next(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2654 {
2655 	return (cmd_cont_common(addr, flags, argc, argv,
2656 	    &mdb_tgt_next, "step (over)"));
2657 }
2658 
2659 static int
2660 cmd_cont(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2661 {
2662 	return (cmd_cont_common(addr, flags, argc, argv,
2663 	    &mdb_tgt_continue, "continue"));
2664 }
2665 
2666 #ifndef _KMDB
2667 /*ARGSUSED*/
2668 static int
2669 cmd_run(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2670 {
2671 	if (flags & DCMD_ADDRSPEC)
2672 		return (DCMD_USAGE);
2673 
2674 	if (mdb_tgt_run(mdb.m_target, argc, argv) == -1) {
2675 		if (errno != EMDB_TGT)
2676 			mdb_warn("failed to create new target");
2677 		return (DCMD_ERR);
2678 	}
2679 	return (cmd_cont(NULL, 0, 0, NULL));
2680 }
2681 #endif
2682 
2683 /*
2684  * To simplify the implementation of :d, :z, and ::delete, we use the sp
2685  * parameter to store the criteria for what to delete.  If spec_base is set,
2686  * we delete vespecs with a matching address.  If spec_id is set, we delete
2687  * vespecs with a matching id.  Otherwise, we delete all vespecs.  We bump
2688  * sp->spec_size so the caller can tell how many vespecs were deleted.
2689  */
2690 static int
2691 ve_delete(mdb_tgt_t *t, mdb_tgt_spec_desc_t *sp, int vid, void *data)
2692 {
2693 	mdb_tgt_spec_desc_t spec;
2694 	int status = -1;
2695 
2696 	if (vid < 0)
2697 		return (0); /* skip over target implementation events */
2698 
2699 	if (sp->spec_base != NULL) {
2700 		(void) mdb_tgt_vespec_info(t, vid, &spec, NULL, 0);
2701 		if (sp->spec_base - spec.spec_base < spec.spec_size)
2702 			status = mdb_tgt_vespec_delete(t, vid);
2703 	} else if (sp->spec_id == 0) {
2704 		(void) mdb_tgt_vespec_info(t, vid, &spec, NULL, 0);
2705 		if (!(spec.spec_flags & MDB_TGT_SPEC_STICKY))
2706 			status = mdb_tgt_vespec_delete(t, vid);
2707 	} else if (sp->spec_id == vid)
2708 		status = mdb_tgt_vespec_delete(t, vid);
2709 
2710 	if (status == 0) {
2711 		if (data != NULL)
2712 			strfree(data);
2713 		sp->spec_size++;
2714 	}
2715 
2716 	return (0);
2717 }
2718 
2719 static int
2720 ve_delete_spec(mdb_tgt_spec_desc_t *sp)
2721 {
2722 	(void) mdb_tgt_vespec_iter(mdb.m_target,
2723 	    (mdb_tgt_vespec_f *)ve_delete, sp);
2724 
2725 	if (sp->spec_size == 0) {
2726 		if (sp->spec_id != 0 || sp->spec_base != NULL)
2727 			mdb_warn("no traced events matched description\n");
2728 	}
2729 
2730 	return (DCMD_OK);
2731 }
2732 
2733 /*ARGSUSED*/
2734 static int
2735 cmd_zapall(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2736 {
2737 	mdb_tgt_spec_desc_t spec;
2738 
2739 	if ((flags & DCMD_ADDRSPEC) || argc != 0)
2740 		return (DCMD_USAGE);
2741 
2742 	bzero(&spec, sizeof (spec));
2743 	return (ve_delete_spec(&spec));
2744 }
2745 
2746 static int
2747 cmd_delete(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2748 {
2749 	mdb_tgt_spec_desc_t spec;
2750 
2751 	if (((flags & DCMD_ADDRSPEC) && argc > 0) || argc > 1)
2752 		return (DCMD_USAGE);
2753 
2754 	bzero(&spec, sizeof (spec));
2755 
2756 	if (flags & DCMD_ADDRSPEC)
2757 		spec.spec_base = addr;
2758 	else if (argc == 0)
2759 		spec.spec_base = mdb_get_dot();
2760 	else if (argv->a_type == MDB_TYPE_STRING &&
2761 	    strcmp(argv->a_un.a_str, "all") != 0)
2762 		spec.spec_id = (int)(intmax_t)strtonum(argv->a_un.a_str, 10);
2763 	else if (argv->a_type == MDB_TYPE_IMMEDIATE)
2764 		spec.spec_id = (int)(intmax_t)argv->a_un.a_val;
2765 
2766 	return (ve_delete_spec(&spec));
2767 }
2768 
2769 static void
2770 srcexec_file_help(void)
2771 {
2772 	mdb_printf(
2773 "The library of macros delivered with previous versions of Solaris have been\n"
2774 "superseded by the dcmds and walkers provided by MDB.  See ::help for\n"
2775 "commands that can be used to list the available dcmds and walkers.\n"
2776 "\n"
2777 "Aliases have been created for several of the more popular macros.  To see\n"
2778 "the list of aliased macros, as well as their native MDB equivalents,\n"
2779 "type $M.\n");
2780 
2781 #ifdef _KMDB
2782 	mdb_printf(
2783 "When invoked, the $< and $<< dcmds will consult the macro alias list.  If an\n"
2784 "alias cannot be found, an attempt will be made to locate a data type whose\n"
2785 "name corresponds to the requested macro.  If such a type can be found, it\n"
2786 "will be displayed using the ::print dcmd.\n");
2787 #else
2788 	mdb_printf(
2789 "When invoked, the $< and $<< dcmds will first attempt to locate a macro with\n"
2790 "the indicated name.  If no macro can be found, and if no alias exists for\n"
2791 "this macro, an attempt will be made to locate a data type whose name\n"
2792 "corresponds to the requested macro.  If such a type can be found, it will be\n"
2793 "displayed using the ::print dcmd.\n");
2794 #endif
2795 }
2796 
2797 static void
2798 events_help(void)
2799 {
2800 	mdb_printf("Options:\n"
2801 	    "-a       show all events, including internal debugger events\n"
2802 	    "-v       show verbose display, including inactivity reason\n"
2803 	    "\nOutput Columns:\n"
2804 	    "ID       decimal event specifier id number:\n"
2805 	    "    [ ]  event tracing is enabled\n"
2806 	    "    ( )  event tracing is disabled\n"
2807 	    "    < >  target is currently stopped on this type of event\n\n"
2808 	    "S        event specifier state:\n"
2809 	    "     -   event specifier is idle (not applicable yet)\n"
2810 	    "     +   event specifier is active\n"
2811 	    "     *   event specifier is armed (target program running)\n"
2812 	    "     !   error occurred while attempting to arm event\n\n"
2813 	    "TA       event specifier flags:\n"
2814 	    "     t   event specifier is temporary (delete at next stop)\n"
2815 	    "     T   event specifier is sticky (::delete all has no effect)\n"
2816 	    "     d   event specifier will be disabled when HT = LM\n"
2817 	    "     D   event specifier will be deleted when HT = LM\n"
2818 	    "     s   target will automatically stop when HT = LM\n\n"
2819 	    "HT       hit count (number of times event has occurred)\n"
2820 	    "LM       hit limit (limit for autostop, disable, delete)\n");
2821 }
2822 
2823 static void
2824 dump_help(void)
2825 {
2826 	mdb_printf(
2827 	    "-e    adjust for endianness\n"
2828 	    "      (assumes 4-byte words; use -g to change word size)\n"
2829 #ifdef _KMDB
2830 	    "-f    no effect\n"
2831 #else
2832 	    "-f    dump from object file\n"
2833 #endif
2834 	    "-g n  display bytes in groups of n\n"
2835 	    "      (default is 4; n must be a power of 2, divide line width)\n"
2836 	    "-p    dump from physical memory\n"
2837 	    "-q    don't print ASCII\n"
2838 	    "-r    use relative numbering (automatically sets -u)\n"
2839 	    "-s    elide repeated lines\n"
2840 	    "-t    only read from and display contents of specified addresses\n"
2841 	    "      (default is to read and print entire lines)\n"
2842 	    "-u    un-align output\n"
2843 	    "      (default is to align output at paragraph boundary)\n"
2844 	    "-w n  display n 16-byte paragraphs per line\n"
2845 	    "      (default is 1, maximum is 16)\n");
2846 }
2847 
2848 /*
2849  * Table of built-in dcmds associated with the root 'mdb' module.  Future
2850  * expansion of this program should be done here, or through the external
2851  * loadable module interface.
2852  */
2853 const mdb_dcmd_t mdb_dcmd_builtins[] = {
2854 
2855 	/*
2856 	 * dcmds common to both mdb and kmdb
2857 	 */
2858 	{ ">", "variable-name", "assign variable", cmd_assign_variable },
2859 	{ "/", "fmt-list", "format data from virtual as", cmd_print_core },
2860 	{ "\\", "fmt-list", "format data from physical as", cmd_print_phys },
2861 	{ "@", "fmt-list", "format data from physical as", cmd_print_phys },
2862 	{ "=", "fmt-list", "format immediate value", cmd_print_value },
2863 	{ "$<", "macro-name", "replace input with macro",
2864 	    cmd_exec_file, srcexec_file_help },
2865 	{ "$<<", "macro-name", "source macro",
2866 	    cmd_src_file, srcexec_file_help},
2867 	{ "$%", NULL, NULL, cmd_quit },
2868 	{ "$?", NULL, "print status and registers", cmd_notsup },
2869 	{ "$a", NULL, NULL, cmd_algol },
2870 	{ "$b", "[-av]", "list traced software events",
2871 	    cmd_events, events_help },
2872 	{ "$c", "?[cnt]", "print stack backtrace", cmd_notsup },
2873 	{ "$C", "?[cnt]", "print stack backtrace", cmd_notsup },
2874 	{ "$d", NULL, "get/set default output radix", cmd_radix },
2875 	{ "$D", "?[mode,...]", NULL, cmd_dbmode },
2876 	{ "$e", NULL, "print listing of global symbols", cmd_globals },
2877 	{ "$f", NULL, "print listing of source files", cmd_files },
2878 	{ "$m", "?[name]", "print address space mappings", cmd_mappings },
2879 	{ "$M", NULL, "list macro aliases", cmd_macalias_list },
2880 	{ "$P", "[prompt]", "set debugger prompt string", cmd_prompt },
2881 	{ "$q", NULL, "quit debugger", cmd_quit },
2882 	{ "$Q", NULL, "quit debugger", cmd_quit },
2883 	{ "$r", NULL, "print general-purpose registers", cmd_notsup },
2884 	{ "$s", NULL, "get/set symbol matching distance", cmd_symdist },
2885 	{ "$v", NULL, "print non-zero variables", cmd_nzvars },
2886 	{ "$V", "[mode]", "get/set disassembly mode", cmd_dismode },
2887 	{ "$w", NULL, "get/set output page width", cmd_pgwidth },
2888 	{ "$W", NULL, "re-open target in write mode", cmd_reopen },
2889 	{ ":a", ":[cmd...]", "set read access watchpoint", cmd_oldwpr },
2890 	{ ":b", ":[cmd...]", "breakpoint at the specified address", cmd_oldbp },
2891 	{ ":d", "?[id|all]", "delete traced software events", cmd_delete },
2892 	{ ":p", ":[cmd...]", "set execute access watchpoint", cmd_oldwpx },
2893 	{ ":S", NULL, NULL, cmd_step },
2894 	{ ":w", ":[cmd...]", "set write access watchpoint", cmd_oldwpw },
2895 	{ ":z", NULL, "delete all traced software events", cmd_zapall },
2896 	{ "array", ":[type count] [variable]", "print each array element's "
2897 	    "address", cmd_array },
2898 	{ "bp", "?[+/-dDestT] [-c cmd] [-n count] sym ...", "breakpoint at the "
2899 	    "specified addresses or symbols", cmd_bp, bp_help },
2900 	{ "dcmds", NULL, "list available debugger commands", cmd_dcmds },
2901 	{ "delete", "?[id|all]", "delete traced software events", cmd_delete },
2902 	{ "dis", "?[-abfw] [-n cnt] [addr]", "disassemble near addr", cmd_dis },
2903 	{ "disasms", NULL, "list available disassemblers", cmd_disasms },
2904 	{ "dismode", "[mode]", "get/set disassembly mode", cmd_dismode },
2905 	{ "dmods", "[-l] [mod]", "list loaded debugger modules", cmd_dmods },
2906 	{ "dump", "?[-eqrstu] [-f|-p] [-g bytes] [-w paragraphs]",
2907 	    "dump memory from specified address", cmd_dump, dump_help },
2908 	{ "echo", "args ...", "echo arguments", cmd_echo },
2909 	{ "enum", "?[-x] enum [name]", "print an enumeration", cmd_enum },
2910 	{ "eval", "command", "evaluate the specified command", cmd_eval },
2911 	{ "events", "[-av]", "list traced software events",
2912 	    cmd_events, events_help },
2913 	{ "evset", "?[+/-dDestT] [-c cmd] [-n count] id ...",
2914 	    "set software event specifier attributes", cmd_evset, evset_help },
2915 	{ "files", "[object]", "print listing of source files", cmd_files },
2916 #ifdef __sparc
2917 	{ "findsym", "?[-g] [symbol|addr ...]", "search for symbol references "
2918 	    "in all known functions", cmd_findsym, NULL },
2919 #endif
2920 	{ "formats", NULL, "list format specifiers", cmd_formats },
2921 	{ "grep", "?expr", "print dot if expression is true", cmd_grep },
2922 	{ "head", "-num|-n num", "limit number of elements in pipe", cmd_head,
2923 	    head_help },
2924 	{ "help", "[cmd]", "list commands/command help", cmd_help },
2925 	{ "list", "?type member [variable]",
2926 	    "walk list using member as link pointer", cmd_list },
2927 	{ "map", "?expr", "print dot after evaluating expression", cmd_map },
2928 	{ "mappings", "?[name]", "print address space mappings", cmd_mappings },
2929 	{ "nm", "?[-DPdghnopuvx] [-f format] [-t types] [object]",
2930 	    "print symbols", cmd_nm, nm_help },
2931 	{ "nmadd", ":[-fo] [-e end] [-s size] name",
2932 	    "add name to private symbol table", cmd_nmadd, nmadd_help },
2933 	{ "nmdel", "name", "remove name from private symbol table", cmd_nmdel },
2934 	{ "obey", NULL, NULL, cmd_obey },
2935 	{ "objects", "[-v]", "print load objects information", cmd_objects },
2936 	{ "offsetof", "type member", "print the offset of a given struct "
2937 	    "or union member", cmd_offsetof },
2938 	{ "print", "?[-aCdhiLptx] [-c lim] [-l lim] [type] [member|offset ...]",
2939 	    "print the contents of a data structure", cmd_print, print_help },
2940 	{ "regs", NULL, "print general purpose registers", cmd_notsup },
2941 	{ "set", "[-wF] [+/-o opt] [-s dist] [-I path] [-L path] [-P prompt]",
2942 	    "get/set debugger properties", cmd_set },
2943 	{ "showrev", "[-pv]", "print version information", cmd_showrev },
2944 	{ "sizeof", "type", "print the size of a type", cmd_sizeof },
2945 	{ "stack", "?[cnt]", "print stack backtrace", cmd_notsup },
2946 	{ "stackregs", "?", "print stack backtrace and registers",
2947 	    cmd_notsup },
2948 	{ "status", NULL, "print summary of current target", cmd_notsup },
2949 	{ "term", NULL, "display current terminal type", cmd_term },
2950 	{ "typeset", "[+/-t] var ...", "set variable attributes", cmd_typeset },
2951 	{ "unset", "[name ...]", "unset variables", cmd_unset },
2952 	{ "vars", "[-npt]", "print listing of variables", cmd_vars },
2953 	{ "version", NULL, "print debugger version string", cmd_version },
2954 	{ "vtop", ":[-a as]", "print physical mapping of virtual address",
2955 	    cmd_vtop },
2956 	{ "walk", "?name [variable]", "walk data structure", cmd_walk },
2957 	{ "walkers", NULL, "list available walkers", cmd_walkers },
2958 	{ "whatis", ":[-aikqv]", "given an address, return information",
2959 	    cmd_whatis, whatis_help },
2960 	{ "whence", "[-v] name ...", "show source of walk or dcmd", cmd_which },
2961 	{ "which", "[-v] name ...", "show source of walk or dcmd", cmd_which },
2962 	{ "xdata", NULL, "print list of external data buffers", cmd_xdata },
2963 
2964 #ifdef _KMDB
2965 	/*
2966 	 * dcmds specific to kmdb, or which have kmdb-specific arguments
2967 	 */
2968 	{ "?", "fmt-list", "format data from virtual as", cmd_print_core },
2969 	{ ":c", NULL, "continue target execution", cmd_cont },
2970 	{ ":e", NULL, "step target over next instruction", cmd_next },
2971 	{ ":s", NULL, "single-step target to next instruction", cmd_step },
2972 	{ ":u", NULL, "step target out of current function", cmd_step_out },
2973 	{ "cont", NULL, "continue target execution", cmd_cont },
2974 	{ "load", "[-sd] module", "load debugger module", cmd_load, load_help },
2975 	{ "next", NULL, "step target over next instruction", cmd_next },
2976 	{ "quit", "[-u]", "quit debugger", cmd_quit, quit_help },
2977 	{ "step", "[ over | out ]",
2978 	    "single-step target to next instruction", cmd_step },
2979 	{ "unload", "[-d] module", "unload debugger module", cmd_unload,
2980 	    unload_help },
2981 	{ "wp", ":[+/-dDelstT] [-rwx] [-pi] [-c cmd] [-n count] [-L size]",
2982 	    "set a watchpoint at the specified address", cmd_wp, wp_help },
2983 
2984 #else
2985 	/*
2986 	 * dcmds specific to mdb, or which have mdb-specific arguments
2987 	 */
2988 	{ "?", "fmt-list", "format data from object file", cmd_print_object },
2989 	{ "$>", "[file]", "log session to a file", cmd_old_log },
2990 	{ "$g", "?", "get/set C++ demangling options", cmd_demflags },
2991 	{ "$G", NULL, "enable/disable C++ demangling support", cmd_demangle },
2992 	{ "$i", NULL, "print signals that are ignored", cmd_notsup },
2993 	{ "$l", NULL, "print the representative thread's lwp id", cmd_notsup },
2994 	{ "$p", ":", "change debugger target context", cmd_context },
2995 	{ "$x", NULL, "print floating point registers", cmd_notsup },
2996 	{ "$X", NULL, "print floating point registers", cmd_notsup },
2997 	{ "$y", NULL, "print floating point registers", cmd_notsup },
2998 	{ "$Y", NULL, "print floating point registers", cmd_notsup },
2999 	{ ":A", "?[core|pid]", "attach to process or core file", cmd_notsup },
3000 	{ ":c", "[SIG]", "continue target execution", cmd_cont },
3001 	{ ":e", "[SIG]", "step target over next instruction", cmd_next },
3002 	{ ":i", ":", "ignore signal (delete all matching events)", cmd_notsup },
3003 	{ ":k", NULL, "forcibly kill and release target", cmd_notsup },
3004 	{ ":t", "?[+/-dDestT] [-c cmd] [-n count] SIG ...", "stop on delivery "
3005 	    "of the specified signals", cmd_sigbp, sigbp_help },
3006 	{ ":r", "[ args ... ]", "run a new target process", cmd_run },
3007 	{ ":R", NULL, "release the previously attached process", cmd_notsup },
3008 	{ ":s", "[SIG]", "single-step target to next instruction", cmd_step },
3009 	{ ":u", "[SIG]", "step target out of current function", cmd_step_out },
3010 	{ "attach", "?[core|pid]",
3011 	    "attach to process or core file", cmd_notsup },
3012 	{ "cat", "[file ...]", "concatenate and display files", cmd_cat },
3013 	{ "cont", "[SIG]", "continue target execution", cmd_cont },
3014 	{ "context", ":", "change debugger target context", cmd_context },
3015 	{ "dem", "name ...", "demangle C++ symbol names", cmd_demstr },
3016 	{ "fltbp", "?[+/-dDestT] [-c cmd] [-n count] fault ...",
3017 	    "stop on machine fault", cmd_fltbp, fltbp_help },
3018 	{ "fpregs", NULL, "print floating point registers", cmd_notsup },
3019 	{ "kill", NULL, "forcibly kill and release target", cmd_notsup },
3020 	{ "load", "[-s] module", "load debugger module", cmd_load, load_help },
3021 	{ "log", "[-d | [-e] file]", "log session to a file", cmd_log },
3022 	{ "next", "[SIG]", "step target over next instruction", cmd_next },
3023 	{ "quit", NULL, "quit debugger", cmd_quit },
3024 	{ "release", NULL,
3025 	    "release the previously attached process", cmd_notsup },
3026 	{ "run", "[ args ... ]", "run a new target process", cmd_run },
3027 	{ "sigbp", "?[+/-dDestT] [-c cmd] [-n count] SIG ...", "stop on "
3028 	    "delivery of the specified signals", cmd_sigbp, sigbp_help },
3029 	{ "step", "[ over | out ] [SIG]",
3030 	    "single-step target to next instruction", cmd_step },
3031 	{ "sysbp", "?[+/-dDestT] [-io] [-c cmd] [-n count] syscall ...",
3032 	    "stop on entry or exit from system call", cmd_sysbp, sysbp_help },
3033 	{ "unload", "module", "unload debugger module", cmd_unload },
3034 	{ "wp", ":[+/-dDelstT] [-rwx] [-c cmd] [-n count] [-L size]",
3035 	    "set a watchpoint at the specified address", cmd_wp, wp_help },
3036 #endif
3037 
3038 	{ NULL }
3039 };
3040