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