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