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