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