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