Merge commit '5e2cca1843c61ee0ef1bb95c5dddc9b450b790c6'
[unleashed.git] / usr / src / cmd / mdb / common / mdb / mdb_cmds.c
blob59a540b2eb713e74612139738b89450ab1b7ab0a
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright (c) 2012 by Delphix. All rights reserved.
29 * Copyright (c) 2018 Joyent, Inc. All rights reserved.
30 * Copyright (c) 2013 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
31 * Copyright (c) 2015, 2017 by Delphix. All rights reserved.
32 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
35 #include <sys/elf.h>
36 #include <sys/elf_SPARC.h>
38 #include <libproc.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <fcntl.h>
42 #include <errno.h>
43 #include <alloca.h>
44 #include <libctf.h>
45 #include <ctype.h>
47 #include <mdb/mdb_string.h>
48 #include <mdb/mdb_argvec.h>
49 #include <mdb/mdb_nv.h>
50 #include <mdb/mdb_fmt.h>
51 #include <mdb/mdb_target.h>
52 #include <mdb/mdb_err.h>
53 #include <mdb/mdb_debug.h>
54 #include <mdb/mdb_conf.h>
55 #include <mdb/mdb_module.h>
56 #include <mdb/mdb_modapi.h>
57 #include <mdb/mdb_stdlib.h>
58 #include <mdb/mdb_lex.h>
59 #include <mdb/mdb_io_impl.h>
60 #include <mdb/mdb_help.h>
61 #include <mdb/mdb_disasm.h>
62 #include <mdb/mdb_frame.h>
63 #include <mdb/mdb_evset.h>
64 #include <mdb/mdb_print.h>
65 #include <mdb/mdb_nm.h>
66 #include <mdb/mdb_set.h>
67 #include <mdb/mdb_demangle.h>
68 #include <mdb/mdb_ctf.h>
69 #include <mdb/mdb_whatis.h>
70 #include <mdb/mdb_whatis_impl.h>
71 #include <mdb/mdb_macalias.h>
72 #include <mdb/mdb_tab.h>
73 #include <mdb/mdb_typedef.h>
74 #ifdef _KMDB
75 #include <kmdb/kmdb_kdi.h>
76 #endif
77 #include <mdb/mdb.h>
80 static mdb_tgt_addr_t
81 write_uint8(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t ull, uint_t rdback)
83 uint8_t o, n = (uint8_t)ull;
85 if (rdback && mdb_tgt_aread(mdb.m_target, as, &o, sizeof (o),
86 addr) == -1)
87 return (addr);
89 if (mdb_tgt_awrite(mdb.m_target, as, &n, sizeof (n), addr) == -1)
90 return (addr);
92 if (rdback) {
93 if (mdb_tgt_aread(mdb.m_target, as, &n, sizeof (n), addr) == -1)
94 return (addr);
96 mdb_iob_printf(mdb.m_out, "%-#*lla%16T%-#8x=%8T0x%x\n",
97 mdb_iob_getmargin(mdb.m_out), addr, o, n);
100 return (addr + sizeof (n));
103 static mdb_tgt_addr_t
104 write_uint16(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t ull, uint_t rdback)
106 uint16_t o, n = (uint16_t)ull;
108 if (rdback && mdb_tgt_aread(mdb.m_target, as, &o, sizeof (o),
109 addr) == -1)
110 return (addr);
112 if (mdb_tgt_awrite(mdb.m_target, as, &n, sizeof (n), addr) == -1)
113 return (addr);
115 if (rdback) {
116 if (mdb_tgt_aread(mdb.m_target, as, &n, sizeof (n), addr) == -1)
117 return (addr);
119 mdb_iob_printf(mdb.m_out, "%-#*lla%16T%-#8hx=%8T0x%hx\n",
120 mdb_iob_getmargin(mdb.m_out), addr, o, n);
123 return (addr + sizeof (n));
126 static mdb_tgt_addr_t
127 write_uint32(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t ull, uint_t rdback)
129 uint32_t o, n = (uint32_t)ull;
131 if (rdback && mdb_tgt_aread(mdb.m_target, as, &o, sizeof (o),
132 addr) == -1)
133 return (addr);
135 if (mdb_tgt_awrite(mdb.m_target, as, &n, sizeof (n), addr) == -1)
136 return (addr);
138 if (rdback) {
139 if (mdb_tgt_aread(mdb.m_target, as, &n, sizeof (n), addr) == -1)
140 return (addr);
142 mdb_iob_printf(mdb.m_out, "%-#*lla%16T%-#16x=%8T0x%x\n",
143 mdb_iob_getmargin(mdb.m_out), addr, o, n);
146 return (addr + sizeof (n));
149 static mdb_tgt_addr_t
150 write_uint64(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t n, uint_t rdback)
152 uint64_t o;
154 if (rdback && mdb_tgt_aread(mdb.m_target, as, &o, sizeof (o),
155 addr) == -1)
156 return (addr);
158 if (mdb_tgt_awrite(mdb.m_target, as, &n, sizeof (n), addr) == -1)
159 return (addr);
161 if (rdback) {
162 if (mdb_tgt_aread(mdb.m_target, as, &n, sizeof (n), addr) == -1)
163 return (addr);
165 mdb_iob_printf(mdb.m_out, "%-#*lla%16T%-#24llx=%8T0x%llx\n",
166 mdb_iob_getmargin(mdb.m_out), addr, o, n);
169 return (addr + sizeof (n));
173 * Writes to objects of size 1, 2, 4, or 8 bytes. The function
174 * doesn't care if the object is a number or not (e.g. it could
175 * be a byte array, or a struct) as long as the size of the write
176 * is one of the aforementioned ones.
178 static mdb_tgt_addr_t
179 write_var_uint(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t val, size_t size,
180 uint_t rdback)
182 if (size < sizeof (uint64_t)) {
183 uint64_t max_num = 1ULL << (size * NBBY);
185 if (val >= max_num) {
186 uint64_t write_len = 0;
188 /* count bytes needed for val */
189 while (val != 0) {
190 write_len++;
191 val >>= NBBY;
194 mdb_warn("value too big for the length of the write: "
195 "supplied %llu bytes but maximum is %llu bytes\n",
196 (u_longlong_t)write_len, (u_longlong_t)size);
197 return (addr);
201 switch (size) {
202 case 1:
203 return (write_uint8(as, addr, val, rdback));
204 case 2:
205 return (write_uint16(as, addr, val, rdback));
206 case 4:
207 return (write_uint32(as, addr, val, rdback));
208 case 8:
209 return (write_uint64(as, addr, val, rdback));
210 default:
211 mdb_warn("writes of size %u are not supported\n ", size);
212 return (addr);
216 static mdb_tgt_addr_t
217 write_ctf_uint(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t n, uint_t rdback)
219 mdb_ctf_id_t mid;
220 size_t size;
221 ssize_t type_size;
222 int kind;
224 if (mdb_ctf_lookup_by_addr(addr, &mid) != 0) {
225 mdb_warn("no CTF data found at this address\n");
226 return (addr);
229 kind = mdb_ctf_type_kind(mid);
230 if (kind == CTF_ERR) {
231 mdb_warn("CTF data found but type kind could not be read");
232 return (addr);
235 if (kind == CTF_K_TYPEDEF) {
236 mdb_ctf_id_t temp_id;
237 if (mdb_ctf_type_resolve(mid, &temp_id) != 0) {
238 mdb_warn("failed to resolve type");
239 return (addr);
241 kind = mdb_ctf_type_kind(temp_id);
244 if (kind != CTF_K_INTEGER && kind != CTF_K_POINTER &&
245 kind != CTF_K_ENUM) {
246 mdb_warn("CTF type should be integer, pointer, or enum\n");
247 return (addr);
250 type_size = mdb_ctf_type_size(mid);
251 if (type_size < 0) {
252 mdb_warn("CTF data found but size could not be read");
253 return (addr);
255 size = type_size;
257 return (write_var_uint(as, addr, n, size, rdback));
260 static int
261 write_arglist(mdb_tgt_as_t as, mdb_tgt_addr_t addr,
262 int argc, const mdb_arg_t *argv)
264 mdb_tgt_addr_t (*write_value)(mdb_tgt_as_t, mdb_tgt_addr_t,
265 uint64_t, uint_t);
266 mdb_tgt_addr_t naddr;
267 uintmax_t value;
268 int rdback = mdb.m_flags & MDB_FL_READBACK;
269 size_t i;
271 if (argc == 1) {
272 mdb_warn("expected value to write following %c\n",
273 argv->a_un.a_char);
274 return (DCMD_ERR);
277 switch (argv->a_un.a_char) {
278 case 'v':
279 write_value = write_uint8;
280 break;
281 case 'w':
282 write_value = write_uint16;
283 break;
284 case 'z':
285 write_value = write_ctf_uint;
286 break;
287 case 'W':
288 write_value = write_uint32;
289 break;
290 case 'Z':
291 write_value = write_uint64;
292 break;
295 for (argv++, i = 1; i < argc; i++, argv++) {
296 if (argv->a_type == MDB_TYPE_CHAR) {
297 mdb_warn("expected immediate value instead of '%c'\n",
298 argv->a_un.a_char);
299 return (DCMD_ERR);
302 if (argv->a_type == MDB_TYPE_STRING) {
303 if (mdb_eval(argv->a_un.a_str) == -1) {
304 mdb_warn("failed to write \"%s\"",
305 argv->a_un.a_str);
306 return (DCMD_ERR);
308 value = mdb_nv_get_value(mdb.m_dot);
309 } else
310 value = argv->a_un.a_val;
312 mdb_nv_set_value(mdb.m_dot, addr);
314 if ((naddr = write_value(as, addr, value, rdback)) == addr) {
315 mdb_warn("failed to write %llr at address 0x%llx",
316 value, addr);
317 mdb.m_incr = 0;
318 return (DCMD_ERR);
321 mdb.m_incr = naddr - addr;
322 addr = naddr;
325 return (DCMD_OK);
328 static mdb_tgt_addr_t
329 match_uint16(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t v64, uint64_t m64)
331 uint16_t x, val = (uint16_t)v64, mask = (uint16_t)m64;
333 for (; mdb_tgt_aread(mdb.m_target, as, &x,
334 sizeof (x), addr) == sizeof (x); addr += sizeof (x)) {
336 if ((x & mask) == val) {
337 mdb_iob_printf(mdb.m_out, "%lla\n", addr);
338 break;
341 return (addr);
344 static mdb_tgt_addr_t
345 match_uint32(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t v64, uint64_t m64)
347 uint32_t x, val = (uint32_t)v64, mask = (uint32_t)m64;
349 for (; mdb_tgt_aread(mdb.m_target, as, &x,
350 sizeof (x), addr) == sizeof (x); addr += sizeof (x)) {
352 if ((x & mask) == val) {
353 mdb_iob_printf(mdb.m_out, "%lla\n", addr);
354 break;
357 return (addr);
360 static mdb_tgt_addr_t
361 match_uint64(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t val, uint64_t mask)
363 uint64_t x;
365 for (; mdb_tgt_aread(mdb.m_target, as, &x,
366 sizeof (x), addr) == sizeof (x); addr += sizeof (x)) {
368 if ((x & mask) == val) {
369 mdb_iob_printf(mdb.m_out, "%lla\n", addr);
370 break;
373 return (addr);
376 static int
377 match_arglist(mdb_tgt_as_t as, uint_t flags, mdb_tgt_addr_t addr,
378 int argc, const mdb_arg_t *argv)
380 mdb_tgt_addr_t (*match_value)(mdb_tgt_as_t, mdb_tgt_addr_t,
381 uint64_t, uint64_t);
383 uint64_t args[2] = { 0, -1ULL }; /* [ value, mask ] */
384 size_t i;
386 if (argc < 2) {
387 mdb_warn("expected value following %c\n", argv->a_un.a_char);
388 return (DCMD_ERR);
391 if (argc > 3) {
392 mdb_warn("only value and mask may follow %c\n",
393 argv->a_un.a_char);
394 return (DCMD_ERR);
397 switch (argv->a_un.a_char) {
398 case 'l':
399 match_value = match_uint16;
400 break;
401 case 'L':
402 match_value = match_uint32;
403 break;
404 case 'M':
405 match_value = match_uint64;
406 break;
409 for (argv++, i = 1; i < argc; i++, argv++) {
410 if (argv->a_type == MDB_TYPE_CHAR) {
411 mdb_warn("expected immediate value instead of '%c'\n",
412 argv->a_un.a_char);
413 return (DCMD_ERR);
416 if (argv->a_type == MDB_TYPE_STRING) {
417 if (mdb_eval(argv->a_un.a_str) == -1) {
418 mdb_warn("failed to evaluate \"%s\"",
419 argv->a_un.a_str);
420 return (DCMD_ERR);
422 args[i - 1] = mdb_nv_get_value(mdb.m_dot);
423 } else
424 args[i - 1] = argv->a_un.a_val;
427 addr = match_value(as, addr, args[0], args[1]);
428 mdb_nv_set_value(mdb.m_dot, addr);
431 * In adb(1), the match operators ignore any repeat count that has
432 * been applied to them. We emulate this undocumented property
433 * by returning DCMD_ABORT if our input is not a pipeline.
435 return ((flags & DCMD_PIPE) ? DCMD_OK : DCMD_ABORT);
438 static int
439 argncmp(int argc, const mdb_arg_t *argv, const char *s)
441 for (; *s != '\0'; s++, argc--, argv++) {
442 if (argc == 0 || argv->a_type != MDB_TYPE_CHAR)
443 return (FALSE);
444 if (argv->a_un.a_char != *s)
445 return (FALSE);
447 return (TRUE);
450 static int
451 print_arglist(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint_t flags,
452 int argc, const mdb_arg_t *argv)
454 char buf[MDB_TGT_SYM_NAMLEN];
455 mdb_tgt_addr_t oaddr = addr;
456 mdb_tgt_addr_t naddr;
457 GElf_Sym sym;
458 size_t i, n;
460 if (DCMD_HDRSPEC(flags) && (flags & DCMD_PIPE_OUT) == 0) {
461 const char *fmt;
462 int is_dis;
464 * This is nasty, but necessary for precise adb compatibility.
465 * Detect disassembly format by looking for "ai" or "ia":
467 if (argncmp(argc, argv, "ai")) {
468 fmt = "%-#*lla\n";
469 is_dis = TRUE;
470 } else if (argncmp(argc, argv, "ia")) {
471 fmt = "%-#*lla";
472 is_dis = TRUE;
473 } else {
474 fmt = "%-#*lla%16T";
475 is_dis = FALSE;
479 * If symbolic decoding is on, disassembly is off, and the
480 * address exactly matches a symbol, print the symbol name:
482 if ((mdb.m_flags & MDB_FL_PSYM) && !is_dis &&
483 (as == MDB_TGT_AS_VIRT || as == MDB_TGT_AS_FILE) &&
484 mdb_tgt_lookup_by_addr(mdb.m_target, (uintptr_t)addr,
485 MDB_TGT_SYM_EXACT, buf, sizeof (buf), &sym, NULL) == 0)
486 mdb_iob_printf(mdb.m_out, "%s:\n", buf);
489 * If this is a virtual address, cast it so that it reflects
490 * only the valid component of the address.
492 if (as == MDB_TGT_AS_VIRT)
493 addr = (uintptr_t)addr;
495 mdb_iob_printf(mdb.m_out, fmt,
496 (uint_t)mdb_iob_getmargin(mdb.m_out), addr);
499 if (argc == 0) {
501 * Yes, for you trivia buffs: if you use a format verb and give
502 * no format string, you get: X^"= "i ... note that in adb the
503 * the '=' verb once had 'z' as its default, but then 'z' was
504 * deleted (it was once an alias for 'i') and so =\n now calls
505 * scanform("z") and produces a 'bad modifier' message.
507 static const mdb_arg_t def_argv[] = {
508 { MDB_TYPE_CHAR, MDB_INIT_CHAR('X') },
509 { MDB_TYPE_CHAR, MDB_INIT_CHAR('^') },
510 { MDB_TYPE_STRING, MDB_INIT_STRING("= ") },
511 { MDB_TYPE_CHAR, MDB_INIT_CHAR('i') }
514 argc = sizeof (def_argv) / sizeof (mdb_arg_t);
515 argv = def_argv;
518 mdb_iob_setflags(mdb.m_out, MDB_IOB_INDENT);
520 for (i = 0, n = 1; i < argc; i++, argv++) {
521 switch (argv->a_type) {
522 case MDB_TYPE_CHAR:
523 naddr = mdb_fmt_print(mdb.m_target, as, addr, n,
524 argv->a_un.a_char);
525 mdb.m_incr = naddr - addr;
526 addr = naddr;
527 n = 1;
528 break;
530 case MDB_TYPE_IMMEDIATE:
531 n = argv->a_un.a_val;
532 break;
534 case MDB_TYPE_STRING:
535 mdb_iob_puts(mdb.m_out, argv->a_un.a_str);
536 n = 1;
537 break;
541 mdb.m_incr = addr - oaddr;
542 mdb_iob_clrflags(mdb.m_out, MDB_IOB_INDENT);
543 return (DCMD_OK);
546 static int
547 print_common(mdb_tgt_as_t as, uint_t flags, int argc, const mdb_arg_t *argv)
549 mdb_tgt_addr_t addr = mdb_nv_get_value(mdb.m_dot);
551 if (argc != 0 && argv->a_type == MDB_TYPE_CHAR) {
552 if (strchr("vwzWZ", argv->a_un.a_char))
553 return (write_arglist(as, addr, argc, argv));
554 if (strchr("lLM", argv->a_un.a_char))
555 return (match_arglist(as, flags, addr, argc, argv));
558 return (print_arglist(as, addr, flags, argc, argv));
561 /*ARGSUSED*/
562 static int
563 cmd_print_core(uintptr_t x, uint_t flags, int argc, const mdb_arg_t *argv)
565 return (print_common(MDB_TGT_AS_VIRT, flags, argc, argv));
568 #ifndef _KMDB
569 /*ARGSUSED*/
570 static int
571 cmd_print_object(uintptr_t x, uint_t flags, int argc, const mdb_arg_t *argv)
573 return (print_common(MDB_TGT_AS_FILE, flags, argc, argv));
575 #endif
577 /*ARGSUSED*/
578 static int
579 cmd_print_phys(uintptr_t x, uint_t flags, int argc, const mdb_arg_t *argv)
581 return (print_common(MDB_TGT_AS_PHYS, flags, argc, argv));
584 /*ARGSUSED*/
585 static int
586 cmd_print_value(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
588 uintmax_t ndot, dot = mdb_get_dot();
589 const char *tgt_argv[1];
590 mdb_tgt_t *t;
591 size_t i, n;
593 if (argc == 0) {
594 mdb_warn("expected one or more format characters "
595 "following '='\n");
596 return (DCMD_ERR);
599 tgt_argv[0] = (const char *)&dot;
600 t = mdb_tgt_create(mdb_value_tgt_create, 0, 1, tgt_argv);
601 mdb_iob_setflags(mdb.m_out, MDB_IOB_INDENT);
603 for (i = 0, n = 1; i < argc; i++, argv++) {
604 switch (argv->a_type) {
605 case MDB_TYPE_CHAR:
606 ndot = mdb_fmt_print(t, MDB_TGT_AS_VIRT,
607 dot, n, argv->a_un.a_char);
608 if (argv->a_un.a_char == '+' ||
609 argv->a_un.a_char == '-')
610 dot = ndot;
611 n = 1;
612 break;
614 case MDB_TYPE_IMMEDIATE:
615 n = argv->a_un.a_val;
616 break;
618 case MDB_TYPE_STRING:
619 mdb_iob_puts(mdb.m_out, argv->a_un.a_str);
620 n = 1;
621 break;
625 mdb_iob_clrflags(mdb.m_out, MDB_IOB_INDENT);
626 mdb_nv_set_value(mdb.m_dot, dot);
627 mdb.m_incr = 0;
629 mdb_tgt_destroy(t);
630 return (DCMD_OK);
633 /*ARGSUSED*/
634 static int
635 cmd_assign_variable(uintptr_t addr, uint_t flags,
636 int argc, const mdb_arg_t *argv)
638 uintmax_t dot = mdb_nv_get_value(mdb.m_dot);
639 const char *p;
640 mdb_var_t *v;
642 if (argc == 2) {
643 if (argv->a_type != MDB_TYPE_CHAR) {
644 mdb_warn("improper arguments following '>' operator\n");
645 return (DCMD_ERR);
648 switch (argv->a_un.a_char) {
649 case 'c':
650 addr = *((uchar_t *)&addr);
651 break;
652 case 's':
653 addr = *((ushort_t *)&addr);
654 break;
655 case 'i':
656 addr = *((uint_t *)&addr);
657 break;
658 case 'l':
659 addr = *((ulong_t *)&addr);
660 break;
661 default:
662 mdb_warn("%c is not a valid // modifier\n",
663 argv->a_un.a_char);
664 return (DCMD_ERR);
667 dot = addr;
668 argv++;
669 argc--;
672 if (argc != 1 || argv->a_type != MDB_TYPE_STRING) {
673 mdb_warn("expected single variable name following '>'\n");
674 return (DCMD_ERR);
677 if (strlen(argv->a_un.a_str) >= (size_t)MDB_NV_NAMELEN) {
678 mdb_warn("variable names may not exceed %d characters\n",
679 MDB_NV_NAMELEN - 1);
680 return (DCMD_ERR);
683 if ((p = strbadid(argv->a_un.a_str)) != NULL) {
684 mdb_warn("'%c' may not be used in a variable name\n", *p);
685 return (DCMD_ERR);
688 if ((v = mdb_nv_lookup(&mdb.m_nv, argv->a_un.a_str)) == NULL)
689 (void) mdb_nv_insert(&mdb.m_nv, argv->a_un.a_str, NULL, dot, 0);
690 else
691 mdb_nv_set_value(v, dot);
693 mdb.m_incr = 0;
694 return (DCMD_OK);
697 static int
698 print_soutype(const char *sou, uintptr_t addr, uint_t flags)
700 static const char *prefixes[] = { "struct ", "union " };
701 size_t namesz = 7 + strlen(sou) + 1;
702 char *name = mdb_alloc(namesz, UM_SLEEP | UM_GC);
703 mdb_ctf_id_t id;
704 int i;
706 for (i = 0; i < 2; i++) {
707 (void) mdb_snprintf(name, namesz, "%s%s", prefixes[i], sou);
709 if (mdb_ctf_lookup_by_name(name, &id) == 0) {
710 mdb_arg_t v;
711 int rv;
713 v.a_type = MDB_TYPE_STRING;
714 v.a_un.a_str = name;
716 rv = mdb_call_dcmd("print", addr, flags, 1, &v);
717 return (rv);
721 return (DCMD_ERR);
724 static int
725 print_type(const char *name, uintptr_t addr, uint_t flags)
727 mdb_ctf_id_t id;
728 char *sname;
729 size_t snamesz;
730 int rv;
732 if (!(flags & DCMD_ADDRSPEC)) {
733 addr = mdb_get_dot();
734 flags |= DCMD_ADDRSPEC;
737 if ((rv = print_soutype(name, addr, flags)) != DCMD_ERR)
738 return (rv);
740 snamesz = strlen(name) + 3;
741 sname = mdb_zalloc(snamesz, UM_SLEEP | UM_GC);
742 (void) mdb_snprintf(sname, snamesz, "%s_t", name);
744 if (mdb_ctf_lookup_by_name(sname, &id) == 0) {
745 mdb_arg_t v;
746 int rv;
748 v.a_type = MDB_TYPE_STRING;
749 v.a_un.a_str = sname;
751 rv = mdb_call_dcmd("print", addr, flags, 1, &v);
752 return (rv);
755 sname[snamesz - 2] = 's';
756 rv = print_soutype(sname, addr, flags);
757 return (rv);
760 static int
761 exec_alias(const char *fname, uintptr_t addr, uint_t flags)
763 const char *alias;
764 int rv;
766 if ((alias = mdb_macalias_lookup(fname)) == NULL)
767 return (DCMD_ERR);
769 if (flags & DCMD_ADDRSPEC) {
770 size_t sz = sizeof (uintptr_t) * 2 + strlen(alias) + 1;
771 char *addralias = mdb_alloc(sz, UM_SLEEP | UM_GC);
772 (void) mdb_snprintf(addralias, sz, "%p%s", addr, alias);
773 rv = mdb_eval(addralias);
774 } else {
775 rv = mdb_eval(alias);
778 return (rv == -1 ? DCMD_ABORT : DCMD_OK);
781 /*ARGSUSED*/
782 static int
783 cmd_src_file(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
785 const char *fname;
786 mdb_io_t *fio;
787 int rv;
789 if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
790 return (DCMD_USAGE);
792 fname = argv->a_un.a_str;
794 if (flags & DCMD_PIPE_OUT) {
795 mdb_warn("macro files cannot be used as input to a pipeline\n");
796 return (DCMD_ABORT);
799 if ((fio = mdb_fdio_create_path(mdb.m_ipath, fname,
800 O_RDONLY, 0)) != NULL) {
801 mdb_frame_t *fp = mdb.m_frame;
802 int err;
804 mdb_iob_stack_push(&fp->f_istk, mdb.m_in, yylineno);
805 mdb.m_in = mdb_iob_create(fio, MDB_IOB_RDONLY);
806 err = mdb_run();
808 ASSERT(fp == mdb.m_frame);
809 mdb.m_in = mdb_iob_stack_pop(&fp->f_istk);
810 yylineno = mdb_iob_lineno(mdb.m_in);
812 if (err == MDB_ERR_PAGER && mdb.m_fmark != fp)
813 longjmp(fp->f_pcb, err);
815 if (err == MDB_ERR_QUIT || err == MDB_ERR_ABORT ||
816 err == MDB_ERR_SIGINT || err == MDB_ERR_OUTPUT)
817 longjmp(fp->f_pcb, err);
819 return (DCMD_OK);
822 if ((rv = exec_alias(fname, addr, flags)) != DCMD_ERR ||
823 (rv = print_type(fname, addr, flags)) != DCMD_ERR)
824 return (rv);
826 mdb_warn("failed to open %s (see ::help '$<')\n", fname);
827 return (DCMD_ABORT);
830 static int
831 cmd_exec_file(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
833 const char *fname;
834 mdb_io_t *fio;
835 int rv;
838 * The syntax [expr[,count]]$< with no trailing macro file name is
839 * magic in that if count is zero, this command won't be called and
840 * the expression is thus a no-op. If count is non-zero, we get
841 * invoked with argc == 0, and this means abort the current macro.
842 * If our debugger stack depth is greater than one, we may be using
843 * $< from within a previous $<<, so in that case we set m_in to
844 * NULL to force this entire frame to be popped.
846 if (argc == 0) {
847 if (mdb_iob_stack_size(&mdb.m_frame->f_istk) != 0) {
848 mdb_iob_destroy(mdb.m_in);
849 mdb.m_in = mdb_iob_stack_pop(&mdb.m_frame->f_istk);
850 } else if (mdb.m_depth > 1) {
851 mdb_iob_destroy(mdb.m_in);
852 mdb.m_in = NULL;
853 } else
854 mdb_warn("input stack is empty\n");
855 return (DCMD_OK);
858 if ((flags & (DCMD_PIPE | DCMD_PIPE_OUT)) || mdb.m_depth == 1)
859 return (cmd_src_file(addr, flags, argc, argv));
861 if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
862 return (DCMD_USAGE);
864 fname = argv->a_un.a_str;
866 if ((fio = mdb_fdio_create_path(mdb.m_ipath, fname,
867 O_RDONLY, 0)) != NULL) {
868 mdb_iob_destroy(mdb.m_in);
869 mdb.m_in = mdb_iob_create(fio, MDB_IOB_RDONLY);
870 return (DCMD_OK);
873 if ((rv = exec_alias(fname, addr, flags)) != DCMD_ERR ||
874 (rv = print_type(fname, addr, flags)) != DCMD_ERR)
875 return (rv);
877 mdb_warn("failed to open %s (see ::help '$<')\n", fname);
878 return (DCMD_ABORT);
881 #ifndef _KMDB
882 /*ARGSUSED*/
883 static int
884 cmd_cat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
886 int status = DCMD_OK;
887 char buf[BUFSIZ];
888 mdb_iob_t *iob;
889 mdb_io_t *fio;
891 if (flags & DCMD_ADDRSPEC)
892 return (DCMD_USAGE);
894 for (; argc-- != 0; argv++) {
895 if (argv->a_type != MDB_TYPE_STRING) {
896 mdb_warn("expected string argument\n");
897 status = DCMD_ERR;
898 continue;
901 if ((fio = mdb_fdio_create_path(NULL,
902 argv->a_un.a_str, O_RDONLY, 0)) == NULL) {
903 mdb_warn("failed to open %s", argv->a_un.a_str);
904 status = DCMD_ERR;
905 continue;
908 iob = mdb_iob_create(fio, MDB_IOB_RDONLY);
910 while (!(mdb_iob_getflags(iob) & (MDB_IOB_EOF | MDB_IOB_ERR))) {
911 ssize_t len = mdb_iob_read(iob, buf, sizeof (buf));
912 if (len > 0) {
913 if (mdb_iob_write(mdb.m_out, buf, len) < 0) {
914 if (errno != EPIPE)
915 mdb_warn("write failed");
916 status = DCMD_ERR;
917 break;
922 if (mdb_iob_err(iob))
923 mdb_warn("error while reading %s", mdb_iob_name(iob));
925 mdb_iob_destroy(iob);
928 return (status);
930 #endif
932 /*ARGSUSED*/
933 static int
934 cmd_grep(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
936 if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
937 return (DCMD_USAGE);
939 if (mdb_eval(argv->a_un.a_str) == -1)
940 return (DCMD_ABORT);
942 if (mdb_get_dot() != 0)
943 mdb_printf("%lr\n", addr);
945 return (DCMD_OK);
948 /*ARGSUSED*/
949 static int
950 cmd_map(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
952 if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
953 return (DCMD_USAGE);
955 if (mdb_eval(argv->a_un.a_str) == -1)
956 return (DCMD_ABORT);
958 mdb_printf("%llr\n", mdb_get_dot());
959 return (DCMD_OK);
962 /*ARGSUSED*/
963 static int
964 cmd_notsup(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
966 mdb_warn("command is not supported by current target\n");
967 return (DCMD_ERR);
970 /*ARGSUSED*/
971 static int
972 cmd_quit(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
974 #ifdef _KMDB
975 uint_t opt_u = FALSE;
977 if (mdb_getopts(argc, argv,
978 'u', MDB_OPT_SETBITS, TRUE, &opt_u, NULL) != argc)
979 return (DCMD_USAGE);
981 if (opt_u) {
982 if (mdb.m_flags & MDB_FL_NOUNLOAD) {
983 warn("%s\n", mdb_strerror(EMDB_KNOUNLOAD));
984 return (DCMD_ERR);
987 kmdb_kdi_set_unload_request();
989 #endif
991 longjmp(mdb.m_frame->f_pcb, MDB_ERR_QUIT);
992 /*NOTREACHED*/
993 return (DCMD_ERR);
996 #ifdef _KMDB
997 static void
998 quit_help(void)
1000 mdb_printf(
1001 "-u unload the debugger (if not loaded at boot)\n");
1003 #endif
1005 /*ARGSUSED*/
1006 static int
1007 cmd_vars(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1009 uint_t opt_nz = FALSE, opt_tag = FALSE, opt_prt = FALSE;
1010 mdb_var_t *v;
1012 if (mdb_getopts(argc, argv,
1013 'n', MDB_OPT_SETBITS, TRUE, &opt_nz,
1014 'p', MDB_OPT_SETBITS, TRUE, &opt_prt,
1015 't', MDB_OPT_SETBITS, TRUE, &opt_tag, NULL) != argc)
1016 return (DCMD_USAGE);
1018 mdb_nv_rewind(&mdb.m_nv);
1020 while ((v = mdb_nv_advance(&mdb.m_nv)) != NULL) {
1021 if ((opt_tag == FALSE || (v->v_flags & MDB_NV_TAGGED)) &&
1022 (opt_nz == FALSE || mdb_nv_get_value(v) != 0)) {
1023 if (opt_prt) {
1024 mdb_printf("%#llr>%s\n",
1025 mdb_nv_get_value(v), mdb_nv_get_name(v));
1026 } else {
1027 mdb_printf("%s = %llr\n",
1028 mdb_nv_get_name(v), mdb_nv_get_value(v));
1033 return (DCMD_OK);
1036 /*ARGSUSED*/
1037 static int
1038 cmd_nzvars(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1040 uintmax_t value;
1041 mdb_var_t *v;
1043 if (argc != 0)
1044 return (DCMD_USAGE);
1046 mdb_nv_rewind(&mdb.m_nv);
1048 while ((v = mdb_nv_advance(&mdb.m_nv)) != NULL) {
1049 if ((value = mdb_nv_get_value(v)) != 0)
1050 mdb_printf("%s = %llr\n", mdb_nv_get_name(v), value);
1053 return (DCMD_OK);
1056 /*ARGSUSED*/
1057 static int
1058 cmd_radix(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1060 if (argc != 0)
1061 return (DCMD_USAGE);
1063 if (flags & DCMD_ADDRSPEC) {
1064 if (addr < 2 || addr > 16) {
1065 mdb_warn("expected radix from 2 to 16\n");
1066 return (DCMD_ERR);
1068 mdb.m_radix = (int)addr;
1071 mdb_iob_printf(mdb.m_out, "radix = %d base ten\n", mdb.m_radix);
1072 return (DCMD_OK);
1075 /*ARGSUSED*/
1076 static int
1077 cmd_symdist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1079 if (argc != 0)
1080 return (DCMD_USAGE);
1082 if (flags & DCMD_ADDRSPEC)
1083 mdb.m_symdist = addr;
1085 mdb_printf("symbol matching distance = %lr (%s)\n",
1086 mdb.m_symdist, mdb.m_symdist ? "absolute mode" : "smart mode");
1088 return (DCMD_OK);
1091 /*ARGSUSED*/
1092 static int
1093 cmd_pgwidth(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1095 if (argc != 0)
1096 return (DCMD_USAGE);
1098 if (flags & DCMD_ADDRSPEC)
1099 mdb_iob_resize(mdb.m_out, mdb.m_out->iob_rows, addr);
1101 mdb_printf("output page width = %lu\n", mdb.m_out->iob_cols);
1102 return (DCMD_OK);
1105 /*ARGSUSED*/
1106 static int
1107 cmd_reopen(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1109 if (argc != 0)
1110 return (DCMD_USAGE);
1112 if (mdb_tgt_setflags(mdb.m_target, MDB_TGT_F_RDWR) == -1) {
1113 mdb_warn("failed to re-open target for writing");
1114 return (DCMD_ERR);
1117 return (DCMD_OK);
1120 /*ARGSUSED*/
1121 static int
1122 print_xdata(void *ignored, const char *name, const char *desc, size_t nbytes)
1124 mdb_printf("%-24s - %s (%lu bytes)\n", name, desc, (ulong_t)nbytes);
1125 return (0);
1128 /*ARGSUSED*/
1129 static int
1130 cmd_xdata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1132 if (argc != 0 || (flags & DCMD_ADDRSPEC))
1133 return (DCMD_USAGE);
1135 (void) mdb_tgt_xdata_iter(mdb.m_target, print_xdata, NULL);
1136 return (DCMD_OK);
1139 /*ARGSUSED*/
1140 static int
1141 cmd_unset(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1143 mdb_var_t *v;
1144 size_t i;
1146 for (i = 0; i < argc; i++) {
1147 if (argv[i].a_type != MDB_TYPE_STRING) {
1148 mdb_warn("bad option: arg %lu is not a string\n",
1149 (ulong_t)i + 1);
1150 return (DCMD_USAGE);
1154 for (i = 0; i < argc; i++, argv++) {
1155 if ((v = mdb_nv_lookup(&mdb.m_nv, argv->a_un.a_str)) == NULL)
1156 mdb_warn("variable '%s' not defined\n",
1157 argv->a_un.a_str);
1158 else
1159 mdb_nv_remove(&mdb.m_nv, v);
1162 return (DCMD_OK);
1165 #ifndef _KMDB
1166 /*ARGSUSED*/
1167 static int
1168 cmd_log(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1170 uint_t opt_e = FALSE, opt_d = FALSE;
1171 const char *filename = NULL;
1172 int i;
1174 i = mdb_getopts(argc, argv,
1175 'd', MDB_OPT_SETBITS, TRUE, &opt_d,
1176 'e', MDB_OPT_SETBITS, TRUE, &opt_e, NULL);
1178 if ((i != argc && i != argc - 1) || (opt_d && opt_e) ||
1179 (i != argc && argv[i].a_type != MDB_TYPE_STRING) ||
1180 (i != argc && opt_d == TRUE) || (flags & DCMD_ADDRSPEC))
1181 return (DCMD_USAGE);
1183 if (mdb.m_depth != 1) {
1184 mdb_warn("log may not be manipulated in this context\n");
1185 return (DCMD_ABORT);
1188 if (i != argc)
1189 filename = argv[i].a_un.a_str;
1192 * If no arguments were specified, print the log file name (if any)
1193 * and report whether the log is enabled or disabled.
1195 if (argc == 0) {
1196 if (mdb.m_log) {
1197 mdb_printf("%s: logging to \"%s\" is currently %s\n",
1198 mdb.m_pname, IOP_NAME(mdb.m_log),
1199 mdb.m_flags & MDB_FL_LOG ? "enabled" : "disabled");
1200 } else
1201 mdb_printf("%s: no log is active\n", mdb.m_pname);
1202 return (DCMD_OK);
1206 * If the -d option was specified, pop the log i/o object off the
1207 * i/o stack of stdin, stdout, and stderr.
1209 if (opt_d) {
1210 if (mdb.m_flags & MDB_FL_LOG) {
1211 (void) mdb_iob_pop_io(mdb.m_in);
1212 (void) mdb_iob_pop_io(mdb.m_out);
1213 (void) mdb_iob_pop_io(mdb.m_err);
1214 mdb.m_flags &= ~MDB_FL_LOG;
1215 } else
1216 mdb_warn("logging is already disabled\n");
1217 return (DCMD_OK);
1221 * The -e option is the default: (re-)enable logging by pushing
1222 * the log i/o object on to stdin, stdout, and stderr. If we have
1223 * a previous log file, we need to pop it and close it. If we have
1224 * no new log file, push the previous one back on.
1226 if (filename != NULL) {
1227 if (mdb.m_log != NULL) {
1228 if (mdb.m_flags & MDB_FL_LOG) {
1229 (void) mdb_iob_pop_io(mdb.m_in);
1230 (void) mdb_iob_pop_io(mdb.m_out);
1231 (void) mdb_iob_pop_io(mdb.m_err);
1232 mdb.m_flags &= ~MDB_FL_LOG;
1234 mdb_io_rele(mdb.m_log);
1237 mdb.m_log = mdb_fdio_create_path(NULL, filename,
1238 O_CREAT | O_APPEND | O_WRONLY, 0666);
1240 if (mdb.m_log == NULL) {
1241 mdb_warn("failed to open %s", filename);
1242 return (DCMD_ERR);
1246 if (mdb.m_log != NULL) {
1247 mdb_iob_push_io(mdb.m_in, mdb_logio_create(mdb.m_log));
1248 mdb_iob_push_io(mdb.m_out, mdb_logio_create(mdb.m_log));
1249 mdb_iob_push_io(mdb.m_err, mdb_logio_create(mdb.m_log));
1251 mdb_printf("%s: logging to \"%s\"\n", mdb.m_pname, filename);
1252 mdb.m_log = mdb_io_hold(mdb.m_log);
1253 mdb.m_flags |= MDB_FL_LOG;
1255 return (DCMD_OK);
1258 mdb_warn("no log file has been selected\n");
1259 return (DCMD_ERR);
1262 static int
1263 cmd_old_log(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1265 if (argc == 0) {
1266 mdb_arg_t arg = { MDB_TYPE_STRING, MDB_INIT_STRING("-d") };
1267 return (cmd_log(addr, flags, 1, &arg));
1270 return (cmd_log(addr, flags, argc, argv));
1272 #endif
1274 /*ARGSUSED*/
1275 static int
1276 cmd_load(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1278 int i, mode = MDB_MOD_LOCAL;
1280 i = mdb_getopts(argc, argv,
1281 #ifdef _KMDB
1282 'd', MDB_OPT_SETBITS, MDB_MOD_DEFER, &mode,
1283 #endif
1284 'f', MDB_OPT_SETBITS, MDB_MOD_FORCE, &mode,
1285 'g', MDB_OPT_SETBITS, MDB_MOD_GLOBAL, &mode,
1286 's', MDB_OPT_SETBITS, MDB_MOD_SILENT, &mode,
1287 NULL);
1289 argc -= i;
1290 argv += i;
1292 if ((flags & DCMD_ADDRSPEC) || argc != 1 ||
1293 argv->a_type != MDB_TYPE_STRING ||
1294 strchr("+-", argv->a_un.a_str[0]) != NULL)
1295 return (DCMD_USAGE);
1297 if (mdb_module_load(argv->a_un.a_str, mode) < 0)
1298 return (DCMD_ERR);
1300 return (DCMD_OK);
1303 static void
1304 load_help(void)
1306 mdb_printf(
1307 #ifdef _KMDB
1308 "-d defer load until next continue\n"
1309 #endif
1310 "-s load module silently\n");
1313 /*ARGSUSED*/
1314 static int
1315 cmd_unload(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1317 int mode = 0;
1318 int i;
1320 i = mdb_getopts(argc, argv,
1321 #ifdef _KMDB
1322 'd', MDB_OPT_SETBITS, MDB_MOD_DEFER, &mode,
1323 #endif
1324 NULL);
1326 argc -= i;
1327 argv += i;
1329 if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
1330 return (DCMD_USAGE);
1332 if (mdb_module_unload(argv->a_un.a_str, mode) == -1) {
1333 mdb_warn("failed to unload %s", argv->a_un.a_str);
1334 return (DCMD_ERR);
1337 return (DCMD_OK);
1340 #ifdef _KMDB
1341 static void
1342 unload_help(void)
1344 mdb_printf(
1345 "-d defer unload until next continue\n");
1347 #endif
1349 static int
1350 cmd_dbmode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1352 if (argc > 1 || (argc != 0 && (flags & DCMD_ADDRSPEC)))
1353 return (DCMD_USAGE);
1355 if (argc != 0) {
1356 if (argv->a_type != MDB_TYPE_STRING)
1357 return (DCMD_USAGE);
1358 if ((addr = mdb_dstr2mode(argv->a_un.a_str)) != MDB_DBG_HELP)
1359 mdb_dmode(addr);
1360 } else if (flags & DCMD_ADDRSPEC)
1361 mdb_dmode(addr);
1363 mdb_printf("debugging mode = 0x%04x\n", mdb.m_debug);
1364 return (DCMD_OK);
1367 /*ARGSUSED*/
1368 static int
1369 cmd_version(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1371 #ifdef DEBUG
1372 mdb_printf("\r%s (DEBUG)\n", mdb_conf_version());
1373 #else
1374 mdb_printf("\r%s\n", mdb_conf_version());
1375 #endif
1376 return (DCMD_OK);
1379 /*ARGSUSED*/
1380 static int
1381 cmd_algol(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1383 if (mdb.m_flags & MDB_FL_ADB)
1384 mdb_printf("No algol 68 here\n");
1385 else
1386 mdb_printf("No adb here\n");
1387 return (DCMD_OK);
1390 /*ARGSUSED*/
1391 static int
1392 cmd_obey(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1394 if (mdb.m_flags & MDB_FL_ADB)
1395 mdb_printf("CHAPTER 1\n");
1396 else
1397 mdb_printf("No Language H here\n");
1398 return (DCMD_OK);
1401 /*ARGSUSED*/
1402 static int
1403 print_global(void *data, const GElf_Sym *sym, const char *name,
1404 const mdb_syminfo_t *sip, const char *obj)
1406 uintptr_t value;
1408 if (mdb_tgt_vread((mdb_tgt_t *)data, &value, sizeof (value),
1409 (uintptr_t)sym->st_value) == sizeof (value))
1410 mdb_printf("%s(%llr):\t%lr\n", name, sym->st_value, value);
1411 else
1412 mdb_printf("%s(%llr):\t?\n", name, sym->st_value);
1414 return (0);
1417 /*ARGSUSED*/
1418 static int
1419 cmd_globals(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1421 if (argc != 0)
1422 return (DCMD_USAGE);
1424 (void) mdb_tgt_symbol_iter(mdb.m_target, MDB_TGT_OBJ_EVERY,
1425 MDB_TGT_SYMTAB, MDB_TGT_BIND_GLOBAL | MDB_TGT_TYPE_OBJECT |
1426 MDB_TGT_TYPE_FUNC, print_global, mdb.m_target);
1428 return (0);
1431 /*ARGSUSED*/
1432 static int
1433 cmd_eval(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1435 if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
1436 return (DCMD_USAGE);
1438 if (mdb_eval(argv->a_un.a_str) == -1)
1439 return (DCMD_ABORT);
1441 return (DCMD_OK);
1444 /*ARGSUSED*/
1445 static int
1446 print_file(void *data, const GElf_Sym *sym, const char *name,
1447 const mdb_syminfo_t *sip, const char *obj)
1449 int i = *((int *)data);
1451 mdb_printf("%d\t%s\n", i++, name);
1452 *((int *)data) = i;
1453 return (0);
1456 /*ARGSUSED*/
1457 static int
1458 cmd_files(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1460 int i = 1;
1461 const char *obj = MDB_TGT_OBJ_EVERY;
1463 if ((flags & DCMD_ADDRSPEC) || argc > 1)
1464 return (DCMD_USAGE);
1466 if (argc == 1) {
1467 if (argv->a_type != MDB_TYPE_STRING)
1468 return (DCMD_USAGE);
1470 obj = argv->a_un.a_str;
1473 (void) mdb_tgt_symbol_iter(mdb.m_target, obj, MDB_TGT_SYMTAB,
1474 MDB_TGT_BIND_ANY | MDB_TGT_TYPE_FILE, print_file, &i);
1476 return (DCMD_OK);
1479 static const char *
1480 map_name(const mdb_map_t *map, const char *name)
1482 if (map->map_flags & MDB_TGT_MAP_HEAP)
1483 return ("[ heap ]");
1484 if (name != NULL && name[0] != 0)
1485 return (name);
1487 if (map->map_flags & MDB_TGT_MAP_SHMEM)
1488 return ("[ shmem ]");
1489 if (map->map_flags & MDB_TGT_MAP_STACK)
1490 return ("[ stack ]");
1491 if (map->map_flags & MDB_TGT_MAP_ANON)
1492 return ("[ anon ]");
1493 if (map->map_name != NULL)
1494 return (map->map_name);
1495 return ("[ unknown ]");
1498 /*ARGSUSED*/
1499 static int
1500 print_map(void *ignored, const mdb_map_t *map, const char *name)
1502 name = map_name(map, name);
1504 mdb_printf("%?p %?p %?lx %s\n", map->map_base,
1505 map->map_base + map->map_size, map->map_size, name);
1506 return (0);
1509 static int
1510 cmd_mappings(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1512 const mdb_map_t *m;
1514 if (argc > 1 || (argc != 0 && (flags & DCMD_ADDRSPEC)))
1515 return (DCMD_USAGE);
1517 mdb_printf("%<u>%?s %?s %?s %s%</u>\n",
1518 "BASE", "LIMIT", "SIZE", "NAME");
1520 if (flags & DCMD_ADDRSPEC) {
1521 if ((m = mdb_tgt_addr_to_map(mdb.m_target, addr)) == NULL)
1522 mdb_warn("failed to obtain mapping");
1523 else
1524 (void) print_map(NULL, m, NULL);
1526 } else if (argc != 0) {
1527 if (argv->a_type == MDB_TYPE_STRING)
1528 m = mdb_tgt_name_to_map(mdb.m_target, argv->a_un.a_str);
1529 else
1530 m = mdb_tgt_addr_to_map(mdb.m_target, argv->a_un.a_val);
1532 if (m == NULL)
1533 mdb_warn("failed to obtain mapping");
1534 else
1535 (void) print_map(NULL, m, NULL);
1537 } else if (mdb_tgt_mapping_iter(mdb.m_target, print_map, NULL) == -1)
1538 mdb_warn("failed to iterate over mappings");
1540 return (DCMD_OK);
1543 static int
1544 whatis_map_callback(void *wp, const mdb_map_t *map, const char *name)
1546 mdb_whatis_t *w = wp;
1547 uintptr_t cur;
1549 name = map_name(map, name);
1551 while (mdb_whatis_match(w, map->map_base, map->map_size, &cur))
1552 mdb_whatis_report_address(w, cur, "in %s [%p,%p)\n",
1553 name, map->map_base, map->map_base + map->map_size);
1555 return (0);
1558 /*ARGSUSED*/
1560 whatis_run_mappings(mdb_whatis_t *w, void *ignored)
1562 (void) mdb_tgt_mapping_iter(mdb.m_target, whatis_map_callback, w);
1563 return (0);
1566 /*ARGSUSED*/
1567 static int
1568 objects_printversion(void *ignored, const mdb_map_t *map, const char *name)
1570 ctf_file_t *ctfp;
1571 const char *version;
1573 ctfp = mdb_tgt_name_to_ctf(mdb.m_target, name);
1574 if (ctfp == NULL || (version = ctf_label_topmost(ctfp)) == NULL)
1575 version = "Unknown";
1577 mdb_printf("%-28s %s\n", name, version);
1578 return (0);
1581 /*ARGSUSED*/
1582 static int
1583 cmd_objects(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1585 uint_t opt_v = FALSE;
1586 mdb_tgt_map_f *cb;
1588 if ((flags & DCMD_ADDRSPEC) || mdb_getopts(argc, argv,
1589 'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
1590 return (DCMD_USAGE);
1592 if (opt_v) {
1593 cb = objects_printversion;
1594 mdb_printf("%<u>%-28s %s%</u>\n", "NAME", "VERSION");
1595 } else {
1596 cb = print_map;
1597 mdb_printf("%<u>%?s %?s %?s %s%</u>\n",
1598 "BASE", "LIMIT", "SIZE", "NAME");
1601 if (mdb_tgt_object_iter(mdb.m_target, cb, NULL) == -1) {
1602 mdb_warn("failed to iterate over objects");
1603 return (DCMD_ERR);
1606 return (DCMD_OK);
1609 /*ARGSUSED*/
1610 static int
1611 showrev_addversion(void *vers_nv, const mdb_map_t *ignored, const char *object)
1613 ctf_file_t *ctfp;
1614 const char *version = NULL;
1615 char *objname;
1617 objname = mdb_alloc(strlen(object) + 1, UM_SLEEP | UM_GC);
1618 (void) strcpy(objname, object);
1620 if ((ctfp = mdb_tgt_name_to_ctf(mdb.m_target, objname)) != NULL)
1621 version = ctf_label_topmost(ctfp);
1624 * Not all objects have CTF and label data, so set version to "Unknown".
1626 if (version == NULL)
1627 version = "Unknown";
1629 (void) mdb_nv_insert(vers_nv, version, NULL, (uintptr_t)objname,
1630 MDB_NV_OVERLOAD);
1632 return (0);
1635 static int
1636 showrev_ispatch(const char *s)
1638 if (s == NULL)
1639 return (0);
1641 if (*s == 'T')
1642 s++; /* skip T for T-patch */
1644 for (; *s != '\0'; s++) {
1645 if ((*s < '0' || *s > '9') && *s != '-')
1646 return (0);
1649 return (1);
1652 /*ARGSUSED*/
1653 static int
1654 showrev_printobject(mdb_var_t *v, void *ignored)
1656 mdb_printf("%s ", MDB_NV_COOKIE(v));
1657 return (0);
1660 static int
1661 showrev_printversion(mdb_var_t *v, void *showall)
1663 const char *version = mdb_nv_get_name(v);
1664 int patch;
1666 patch = showrev_ispatch(version);
1667 if (patch || (uintptr_t)showall) {
1668 mdb_printf("%s: %s Objects: ",
1669 (patch ? "Patch" : "Version"), version);
1670 (void) mdb_inc_indent(2);
1672 mdb_nv_defn_iter(v, showrev_printobject, NULL);
1674 (void) mdb_dec_indent(2);
1675 mdb_printf("\n");
1678 return (0);
1682 * Display version information for each object in the system.
1683 * Print information about patches only, unless showall is TRUE.
1685 static int
1686 showrev_objectversions(int showall)
1688 mdb_nv_t vers_nv;
1690 (void) mdb_nv_create(&vers_nv, UM_SLEEP | UM_GC);
1691 if (mdb_tgt_object_iter(mdb.m_target, showrev_addversion,
1692 &vers_nv) == -1) {
1693 mdb_warn("failed to iterate over objects");
1694 return (DCMD_ERR);
1697 mdb_nv_sort_iter(&vers_nv, showrev_printversion,
1698 (void *)(uintptr_t)showall, UM_SLEEP | UM_GC);
1699 return (DCMD_OK);
1703 * Display information similar to what showrev(8) displays when invoked
1704 * with no arguments.
1706 static int
1707 showrev_sysinfo(void)
1709 const char *s;
1710 int rc;
1711 struct utsname u;
1713 if ((rc = mdb_tgt_uname(mdb.m_target, &u)) != -1) {
1714 mdb_printf("Hostname: %s\n", u.nodename);
1715 mdb_printf("Release: %s\n", u.release);
1716 mdb_printf("Kernel architecture: %s\n", u.machine);
1720 * Match the order of the showrev(8) output and put "Application
1721 * architecture" before "Kernel version"
1723 if ((s = mdb_tgt_isa(mdb.m_target)) != NULL)
1724 mdb_printf("Application architecture: %s\n", s);
1726 if (rc != -1)
1727 mdb_printf("Kernel version: %s %s %s %s\n",
1728 u.sysname, u.release, u.machine, u.version);
1730 if ((s = mdb_tgt_platform(mdb.m_target)) != NULL)
1731 mdb_printf("Platform: %s\n", s);
1733 return (DCMD_OK);
1736 /*ARGSUSED*/
1737 static int
1738 cmd_showrev(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1740 uint_t opt_p = FALSE, opt_v = FALSE;
1742 if ((flags & DCMD_ADDRSPEC) || mdb_getopts(argc, argv,
1743 'p', MDB_OPT_SETBITS, TRUE, &opt_p,
1744 'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
1745 return (DCMD_USAGE);
1747 if (opt_p || opt_v)
1748 return (showrev_objectversions(opt_v));
1749 else
1750 return (showrev_sysinfo());
1754 static int
1755 dis_str2addr(const char *s, uintptr_t *addr)
1757 GElf_Sym sym;
1759 if (s[0] >= '0' && s[0] <= '9') {
1760 *addr = (uintptr_t)mdb_strtoull(s);
1761 return (0);
1764 if (mdb_tgt_lookup_by_name(mdb.m_target,
1765 MDB_TGT_OBJ_EVERY, s, &sym, NULL) == -1) {
1766 mdb_warn("symbol '%s' not found\n", s);
1767 return (-1);
1770 *addr = (uintptr_t)sym.st_value;
1771 return (0);
1774 static int
1775 cmd_dis(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1777 mdb_tgt_t *tgt = mdb.m_target;
1778 mdb_disasm_t *dis = mdb.m_disasm;
1780 uintptr_t oaddr, naddr;
1781 mdb_tgt_as_t as;
1782 mdb_tgt_status_t st;
1783 char buf[BUFSIZ];
1784 GElf_Sym sym;
1785 int i;
1787 uint_t opt_f = FALSE; /* File-mode off by default */
1788 uint_t opt_w = FALSE; /* Window mode off by default */
1789 uint_t opt_a = FALSE; /* Raw-address mode off by default */
1790 uint_t opt_b = FALSE; /* Address & symbols off by default */
1791 uintptr_t n = -1UL; /* Length of window in instructions */
1792 uintptr_t eaddr = 0; /* Ending address; 0 if limited by n */
1794 i = mdb_getopts(argc, argv,
1795 'f', MDB_OPT_SETBITS, TRUE, &opt_f,
1796 'w', MDB_OPT_SETBITS, TRUE, &opt_w,
1797 'a', MDB_OPT_SETBITS, TRUE, &opt_a,
1798 'b', MDB_OPT_SETBITS, TRUE, &opt_b,
1799 'n', MDB_OPT_UINTPTR, &n, NULL);
1802 * Disgusting argument post-processing ... basically the idea is to get
1803 * the target address into addr, which we do by using the specified
1804 * expression value, looking up a string as a symbol name, or by
1805 * using the address specified as dot.
1807 if (i != argc) {
1808 if (argc != 0 && (argc - i) == 1) {
1809 if (argv[i].a_type == MDB_TYPE_STRING) {
1810 if (argv[i].a_un.a_str[0] == '-')
1811 return (DCMD_USAGE);
1813 if (dis_str2addr(argv[i].a_un.a_str, &addr))
1814 return (DCMD_ERR);
1815 } else
1816 addr = argv[i].a_un.a_val;
1817 } else
1818 return (DCMD_USAGE);
1822 * If we're not in window mode yet, and some type of arguments were
1823 * specified, see if the address corresponds nicely to a function.
1824 * If not, turn on window mode; otherwise disassemble the function.
1826 if (opt_w == FALSE && (argc != i || (flags & DCMD_ADDRSPEC))) {
1827 if (mdb_tgt_lookup_by_addr(tgt, addr,
1828 MDB_TGT_SYM_EXACT, buf, sizeof (buf), &sym, NULL) == 0 &&
1829 GELF_ST_TYPE(sym.st_info) == STT_FUNC) {
1831 * If the symbol has a size then set our end address to
1832 * be the end of the function symbol we just located.
1834 if (sym.st_size != 0)
1835 eaddr = addr + (uintptr_t)sym.st_size;
1836 } else
1837 opt_w = TRUE;
1841 * Window-mode doesn't make sense in a loop.
1843 if (flags & DCMD_LOOP)
1844 opt_w = FALSE;
1847 * If -n was explicit, limit output to n instructions;
1848 * otherwise set n to some reasonable default
1850 if (n != -1UL)
1851 eaddr = 0;
1852 else
1853 n = 10;
1856 * If the state is IDLE (i.e. no address space), turn on -f.
1858 if (mdb_tgt_status(tgt, &st) == 0 && st.st_state == MDB_TGT_IDLE)
1859 opt_f = TRUE;
1861 if (opt_f)
1862 as = MDB_TGT_AS_FILE;
1863 else
1864 as = MDB_TGT_AS_VIRT;
1866 if (opt_w == FALSE) {
1867 n++;
1868 while ((eaddr == 0 && n-- != 0) || (addr < eaddr)) {
1869 naddr = mdb_dis_ins2str(dis, tgt, as,
1870 buf, sizeof (buf), addr);
1871 if (naddr == addr)
1872 return (DCMD_ERR);
1873 if (opt_a)
1874 mdb_printf("%-#32p%8T%s\n", addr, buf);
1875 else if (opt_b)
1876 mdb_printf("%-#?p %-#32a%8T%s\n",
1877 addr, addr, buf);
1878 else
1879 mdb_printf("%-#32a%8T%s\n", addr, buf);
1880 addr = naddr;
1883 } else {
1885 for (oaddr = mdb_dis_previns(dis, tgt, as, addr, n);
1886 oaddr < addr; oaddr = naddr) {
1887 naddr = mdb_dis_ins2str(dis, tgt, as,
1888 buf, sizeof (buf), oaddr);
1889 if (naddr == oaddr)
1890 return (DCMD_ERR);
1891 if (opt_a)
1892 mdb_printf("%-#32p%8T%s\n", oaddr, buf);
1893 else if (opt_b)
1894 mdb_printf("%-#?p %-#32a%8T%s\n",
1895 oaddr, oaddr, buf);
1896 else
1897 mdb_printf("%-#32a%8T%s\n", oaddr, buf);
1900 if ((naddr = mdb_dis_ins2str(dis, tgt, as,
1901 buf, sizeof (buf), addr)) == addr)
1902 return (DCMD_ERR);
1904 mdb_printf("%<b>");
1905 mdb_flush();
1906 if (opt_a)
1907 mdb_printf("%-#32p%8T%s%", addr, buf);
1908 else if (opt_b)
1909 mdb_printf("%-#?p %-#32a%8T%s", addr, addr, buf);
1910 else
1911 mdb_printf("%-#32a%8T%s%", addr, buf);
1912 mdb_printf("%</b>\n");
1914 for (addr = naddr; n-- != 0; addr = naddr) {
1915 naddr = mdb_dis_ins2str(dis, tgt, as,
1916 buf, sizeof (buf), addr);
1917 if (naddr == addr)
1918 return (DCMD_ERR);
1919 if (opt_a)
1920 mdb_printf("%-#32p%8T%s\n", addr, buf);
1921 else if (opt_b)
1922 mdb_printf("%-#?p %-#32a%8T%s\n",
1923 addr, addr, buf);
1924 else
1925 mdb_printf("%-#32a%8T%s\n", addr, buf);
1929 mdb_set_dot(addr);
1930 return (DCMD_OK);
1933 /*ARGSUSED*/
1934 static int
1935 walk_step(uintptr_t addr, const void *data, void *private)
1937 mdb_printf("%#lr\n", addr);
1938 return (WALK_NEXT);
1941 static int
1942 cmd_walk(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1944 int status;
1946 if (argc < 1 || argc > 2 || argv[0].a_type != MDB_TYPE_STRING ||
1947 argv[argc - 1].a_type != MDB_TYPE_STRING)
1948 return (DCMD_USAGE);
1950 if (argc > 1) {
1951 const char *name = argv[1].a_un.a_str;
1952 mdb_var_t *v = mdb_nv_lookup(&mdb.m_nv, name);
1953 const char *p;
1955 if (v != NULL && (v->v_flags & MDB_NV_RDONLY) != 0) {
1956 mdb_warn("variable %s is read-only\n", name);
1957 return (DCMD_ABORT);
1960 if (v == NULL && (p = strbadid(name)) != NULL) {
1961 mdb_warn("'%c' may not be used in a variable "
1962 "name\n", *p);
1963 return (DCMD_ABORT);
1966 if (v == NULL && (v = mdb_nv_insert(&mdb.m_nv,
1967 name, NULL, 0, 0)) == NULL)
1968 return (DCMD_ERR);
1971 * If there already exists a vcb for this variable, we may be
1972 * calling ::walk in a loop. We only create a vcb for this
1973 * variable on the first invocation.
1975 if (mdb_vcb_find(v, mdb.m_frame) == NULL)
1976 mdb_vcb_insert(mdb_vcb_create(v), mdb.m_frame);
1979 if (flags & DCMD_ADDRSPEC)
1980 status = mdb_pwalk(argv->a_un.a_str, walk_step, NULL, addr);
1981 else
1982 status = mdb_walk(argv->a_un.a_str, walk_step, NULL);
1984 if (status == -1) {
1985 mdb_warn("failed to perform walk");
1986 return (DCMD_ERR);
1989 return (DCMD_OK);
1992 static int
1993 cmd_walk_tab(mdb_tab_cookie_t *mcp, uint_t flags, int argc,
1994 const mdb_arg_t *argv)
1996 if (argc > 1)
1997 return (1);
1999 if (argc == 1) {
2000 ASSERT(argv[0].a_type == MDB_TYPE_STRING);
2001 return (mdb_tab_complete_walker(mcp, argv[0].a_un.a_str));
2004 if (argc == 0 && flags & DCMD_TAB_SPACE)
2005 return (mdb_tab_complete_walker(mcp, NULL));
2007 return (1);
2010 static ssize_t
2011 mdb_partial_xread(void *buf, size_t nbytes, uintptr_t addr, void *arg)
2013 ssize_t (*fp)(mdb_tgt_t *, const void *, size_t, uintptr_t) =
2014 (ssize_t (*)(mdb_tgt_t *, const void *, size_t, uintptr_t))arg;
2016 return (fp(mdb.m_target, buf, nbytes, addr));
2019 /* ARGSUSED3 */
2020 static ssize_t
2021 mdb_partial_pread(void *buf, size_t nbytes, physaddr_t addr, void *arg)
2023 return (mdb_tgt_pread(mdb.m_target, buf, nbytes, addr));
2027 static int
2028 cmd_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2030 uint_t dflags =
2031 MDB_DUMP_ALIGN | MDB_DUMP_NEWDOT | MDB_DUMP_ASCII | MDB_DUMP_HEADER;
2032 uint_t phys = FALSE;
2033 uint_t file = FALSE;
2034 uintptr_t group = 4;
2035 uintptr_t length = 0;
2036 uintptr_t width = 1;
2037 mdb_tgt_status_t st;
2038 int error;
2040 if (mdb_getopts(argc, argv,
2041 'e', MDB_OPT_SETBITS, MDB_DUMP_ENDIAN, &dflags,
2042 'f', MDB_OPT_SETBITS, TRUE, &file,
2043 'g', MDB_OPT_UINTPTR, &group,
2044 'l', MDB_OPT_UINTPTR, &length,
2045 'p', MDB_OPT_SETBITS, TRUE, &phys,
2046 'q', MDB_OPT_CLRBITS, MDB_DUMP_ASCII, &dflags,
2047 'r', MDB_OPT_SETBITS, MDB_DUMP_RELATIVE, &dflags,
2048 's', MDB_OPT_SETBITS, MDB_DUMP_SQUISH, &dflags,
2049 't', MDB_OPT_SETBITS, MDB_DUMP_TRIM, &dflags,
2050 'u', MDB_OPT_CLRBITS, MDB_DUMP_ALIGN, &dflags,
2051 'v', MDB_OPT_SETBITS, MDB_DUMP_PEDANT, &dflags,
2052 'w', MDB_OPT_UINTPTR, &width, NULL) != argc)
2053 return (DCMD_USAGE);
2055 if ((phys && file) ||
2056 (width == 0) || (width > 0x10) ||
2057 (group == 0) || (group > 0x100) ||
2058 (mdb.m_dcount > 1 && length > 0))
2059 return (DCMD_USAGE);
2060 if (length == 0)
2061 length = mdb.m_dcount;
2064 * If neither -f nor -p were specified and the state is IDLE (i.e. no
2065 * address space), turn on -p. This is so we can read large files.
2067 if (phys == FALSE && file == FALSE && mdb_tgt_status(mdb.m_target,
2068 &st) == 0 && st.st_state == MDB_TGT_IDLE)
2069 phys = TRUE;
2071 dflags |= MDB_DUMP_GROUP(group) | MDB_DUMP_WIDTH(width);
2072 if (phys)
2073 error = mdb_dump64(mdb_get_dot(), length, dflags,
2074 mdb_partial_pread, NULL);
2075 else if (file)
2076 error = mdb_dumpptr(addr, length, dflags,
2077 mdb_partial_xread, (void *)mdb_tgt_fread);
2078 else
2079 error = mdb_dumpptr(addr, length, dflags,
2080 mdb_partial_xread, (void *)mdb_tgt_vread);
2082 return (((flags & DCMD_LOOP) || (error == -1)) ? DCMD_ABORT : DCMD_OK);
2085 /*ARGSUSED*/
2086 static int
2087 cmd_echo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2089 if (flags & DCMD_ADDRSPEC)
2090 return (DCMD_USAGE);
2092 for (; argc-- != 0; argv++) {
2093 if (argv->a_type == MDB_TYPE_STRING)
2094 mdb_printf("%s ", argv->a_un.a_str);
2095 else
2096 mdb_printf("%llr ", argv->a_un.a_val);
2099 mdb_printf("\n");
2100 return (DCMD_OK);
2103 /*ARGSUSED*/
2104 static int
2105 cmd_head(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2107 uint64_t cnt = 10;
2108 const char *c;
2109 mdb_pipe_t p;
2111 if (!flags & DCMD_PIPE)
2112 return (DCMD_USAGE);
2114 if (argc == 1 || argc == 2) {
2115 const char *num;
2117 if (argc == 1) {
2118 if (argv[0].a_type != MDB_TYPE_STRING ||
2119 *argv[0].a_un.a_str != '-')
2120 return (DCMD_USAGE);
2122 num = argv[0].a_un.a_str + 1;
2124 } else {
2125 if (argv[0].a_type != MDB_TYPE_STRING ||
2126 strcmp(argv[0].a_un.a_str, "-n") != 0)
2127 return (DCMD_USAGE);
2129 num = argv[1].a_un.a_str;
2132 for (cnt = 0, c = num; *c != '\0' && isdigit(*c); c++)
2133 cnt = cnt * 10 + (*c - '0');
2135 if (*c != '\0')
2136 return (DCMD_USAGE);
2138 } else if (argc != 0) {
2139 return (DCMD_USAGE);
2142 mdb_get_pipe(&p);
2144 if (p.pipe_data == NULL)
2145 return (DCMD_OK);
2146 p.pipe_len = MIN(p.pipe_len, cnt);
2148 if (flags & DCMD_PIPE_OUT) {
2149 mdb_set_pipe(&p);
2150 } else {
2151 while (p.pipe_len-- > 0)
2152 mdb_printf("%lx\n", *p.pipe_data++);
2155 return (DCMD_OK);
2158 static void
2159 head_help(void)
2161 mdb_printf(
2162 "-n num\n or\n"
2163 "-num pass only the first `num' elements in the pipe.\n"
2164 "\n%<b>Note:%</b> `num' is a decimal number.\n");
2167 static int
2168 cmd_typeset(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2170 int add_tag = 0, del_tag = 0;
2171 const char *p;
2172 mdb_var_t *v;
2174 if (argc == 0)
2175 return (cmd_vars(addr, flags, argc, argv));
2177 if (argv->a_type == MDB_TYPE_STRING && (argv->a_un.a_str[0] == '-' ||
2178 argv->a_un.a_str[0] == '+')) {
2179 if (argv->a_un.a_str[1] != 't')
2180 return (DCMD_USAGE);
2181 if (argv->a_un.a_str[0] == '-')
2182 add_tag++;
2183 else
2184 del_tag++;
2185 argc--;
2186 argv++;
2189 if (!(flags & DCMD_ADDRSPEC))
2190 addr = 0; /* set variables to zero unless explicit addr given */
2192 for (; argc-- != 0; argv++) {
2193 if (argv->a_type != MDB_TYPE_STRING)
2194 continue;
2196 if (argv->a_un.a_str[0] == '-' || argv->a_un.a_str[0] == '+') {
2197 mdb_warn("ignored bad option -- %s\n",
2198 argv->a_un.a_str);
2199 continue;
2202 if ((p = strbadid(argv->a_un.a_str)) != NULL) {
2203 mdb_warn("'%c' may not be used in a variable "
2204 "name\n", *p);
2205 return (DCMD_ERR);
2208 if ((v = mdb_nv_lookup(&mdb.m_nv, argv->a_un.a_str)) == NULL) {
2209 v = mdb_nv_insert(&mdb.m_nv, argv->a_un.a_str,
2210 NULL, addr, 0);
2211 } else if (flags & DCMD_ADDRSPEC)
2212 mdb_nv_set_value(v, addr);
2214 if (v != NULL) {
2215 if (add_tag)
2216 v->v_flags |= MDB_NV_TAGGED;
2217 if (del_tag)
2218 v->v_flags &= ~MDB_NV_TAGGED;
2222 return (DCMD_OK);
2225 #ifndef _KMDB
2226 /*ARGSUSED*/
2227 static int
2228 cmd_context(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2230 if (argc != 0 || !(flags & DCMD_ADDRSPEC))
2231 return (DCMD_USAGE);
2233 if (mdb_tgt_setcontext(mdb.m_target, (void *)addr) == 0)
2234 return (DCMD_OK);
2236 return (DCMD_ERR);
2238 #endif
2240 /*ARGSUSED*/
2241 static int
2242 cmd_prompt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2244 const char *p = "";
2246 if (argc != 0) {
2247 if (argc > 1 || argv->a_type != MDB_TYPE_STRING)
2248 return (DCMD_USAGE);
2249 p = argv->a_un.a_str;
2252 (void) mdb_set_prompt(p);
2253 return (DCMD_OK);
2256 /*ARGSUSED*/
2257 static int
2258 cmd_term(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2260 mdb_printf("%s\n", mdb.m_termtype);
2262 return (DCMD_OK);
2265 /*ARGSUSED*/
2266 static int
2267 cmd_vtop(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2269 physaddr_t pa;
2270 mdb_tgt_as_t as = MDB_TGT_AS_VIRT;
2272 if (mdb_getopts(argc, argv, 'a', MDB_OPT_UINTPTR, (uintptr_t *)&as,
2273 NULL) != argc)
2274 return (DCMD_USAGE);
2276 if (mdb_tgt_vtop(mdb.m_target, as, addr, &pa) == -1) {
2277 mdb_warn("failed to get physical mapping");
2278 return (DCMD_ERR);
2281 if (flags & DCMD_PIPE_OUT)
2282 mdb_printf("%llr\n", pa);
2283 else
2284 mdb_printf("virtual %lr mapped to physical %llr\n", addr, pa);
2285 return (DCMD_OK);
2288 #define EVENTS_OPT_A 0x1 /* ::events -a (show all events) */
2289 #define EVENTS_OPT_V 0x2 /* ::events -v (verbose display) */
2291 static const char *
2292 event_action(const mdb_tgt_spec_desc_t *sp)
2294 if (!(sp->spec_flags & MDB_TGT_SPEC_HIDDEN) && sp->spec_data != NULL)
2295 return (sp->spec_data);
2297 return ("-");
2300 static void
2301 print_evsep(void)
2303 static const char dash20[] = "--------------------";
2304 mdb_printf("----- - -- -- -- %s%s --%s\n", dash20, dash20, dash20);
2307 /*ARGSUSED*/
2308 static int
2309 print_event(mdb_tgt_t *t, void *private, int vid, void *data)
2311 uint_t opts = (uint_t)(uintptr_t)private;
2312 mdb_tgt_spec_desc_t sp;
2313 char s1[41], s2[22];
2314 const char *s2str;
2315 int visible;
2317 (void) mdb_tgt_vespec_info(t, vid, &sp, s1, sizeof (s1));
2318 visible = !(sp.spec_flags & (MDB_TGT_SPEC_HIDDEN|MDB_TGT_SPEC_DELETED));
2320 if ((opts & EVENTS_OPT_A) || visible) {
2321 int encoding = (!(sp.spec_flags & MDB_TGT_SPEC_DISABLED)) |
2322 (!(sp.spec_flags & MDB_TGT_SPEC_MATCHED) << 1);
2324 char ldelim = "<<(["[encoding];
2325 char rdelim = ">>)]"[encoding];
2327 char state = "0-+*!"[sp.spec_state];
2329 char tflag = "T "[!(sp.spec_flags & MDB_TGT_SPEC_STICKY)];
2330 char aflag = "d "[!(sp.spec_flags & MDB_TGT_SPEC_AUTODIS)];
2332 if (sp.spec_flags & MDB_TGT_SPEC_TEMPORARY)
2333 tflag = 't'; /* TEMP takes precedence over STICKY */
2334 if (sp.spec_flags & MDB_TGT_SPEC_AUTODEL)
2335 aflag = 'D'; /* AUTODEL takes precedence over AUTODIS */
2336 if (sp.spec_flags & MDB_TGT_SPEC_AUTOSTOP)
2337 aflag = 's'; /* AUTOSTOP takes precedence over both */
2339 if (opts & EVENTS_OPT_V) {
2340 if (sp.spec_state == MDB_TGT_SPEC_IDLE ||
2341 sp.spec_state == MDB_TGT_SPEC_ERROR)
2342 s2str = mdb_strerror(sp.spec_errno);
2343 else
2344 s2str = "-";
2345 } else
2346 s2str = event_action(&sp);
2348 if (mdb_snprintf(s2, sizeof (s2), "%s", s2str) >= sizeof (s2))
2349 (void) strabbr(s2, sizeof (s2));
2351 if (vid > -10 && vid < 10)
2352 mdb_printf("%c%2d %c", ldelim, vid, rdelim);
2353 else
2354 mdb_printf("%c%3d%c", ldelim, vid, rdelim);
2356 mdb_printf(" %c %c%c %2u %2u %-40s %-21s\n",
2357 state, tflag, aflag, sp.spec_hits, sp.spec_limit, s1, s2);
2359 if (opts & EVENTS_OPT_V) {
2360 mdb_printf("%-17s%s\n", "", event_action(&sp));
2361 print_evsep();
2365 return (0);
2368 /*ARGSUSED*/
2369 static int
2370 cmd_events(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2372 uint_t opts = 0;
2374 if ((flags & DCMD_ADDRSPEC) || mdb_getopts(argc, argv,
2375 'a', MDB_OPT_SETBITS, EVENTS_OPT_A, &opts,
2376 'v', MDB_OPT_SETBITS, EVENTS_OPT_V, &opts, NULL) != argc)
2377 return (DCMD_USAGE);
2380 if (opts & EVENTS_OPT_V) {
2381 mdb_printf(" ID S TA HT LM %-40s %-21s\n%-17s%s\n",
2382 "Description", "Status", "", "Action");
2383 } else {
2384 mdb_printf(" ID S TA HT LM %-40s %-21s\n",
2385 "Description", "Action");
2388 print_evsep();
2389 return (mdb_tgt_vespec_iter(mdb.m_target, print_event,
2390 (void *)(uintptr_t)opts));
2393 static int
2394 tgt_status(const mdb_tgt_status_t *tsp)
2396 const char *format;
2397 char buf[BUFSIZ];
2399 if (tsp->st_flags & MDB_TGT_BUSY)
2400 return (DCMD_OK);
2402 if (tsp->st_pc != 0) {
2403 if (mdb_dis_ins2str(mdb.m_disasm, mdb.m_target, MDB_TGT_AS_VIRT,
2404 buf, sizeof (buf), tsp->st_pc) != tsp->st_pc)
2405 format = "target stopped at:\n%-#16a%8T%s\n";
2406 else
2407 format = "target stopped at %a:\n";
2408 mdb_warn(format, tsp->st_pc, buf);
2411 switch (tsp->st_state) {
2412 case MDB_TGT_IDLE:
2413 mdb_warn("target is idle\n");
2414 break;
2415 case MDB_TGT_RUNNING:
2416 if (tsp->st_flags & MDB_TGT_DSTOP)
2417 mdb_warn("target is running, stop directive pending\n");
2418 else
2419 mdb_warn("target is running\n");
2420 break;
2421 case MDB_TGT_STOPPED:
2422 if (tsp->st_pc == 0)
2423 mdb_warn("target is stopped\n");
2424 break;
2425 case MDB_TGT_UNDEAD:
2426 mdb_warn("target has terminated\n");
2427 break;
2428 case MDB_TGT_DEAD:
2429 mdb_warn("target is a core dump\n");
2430 break;
2431 case MDB_TGT_LOST:
2432 mdb_warn("target is no longer under debugger control\n");
2433 break;
2436 mdb_set_dot(tsp->st_pc);
2437 return (DCMD_OK);
2441 * mdb continue/step commands take an optional signal argument, but the
2442 * corresponding kmdb versions don't.
2444 #ifdef _KMDB
2445 #define CONT_MAXARGS 0 /* no optional SIG argument */
2446 #else
2447 #define CONT_MAXARGS 1
2448 #endif
2450 /*ARGSUSED*/
2451 static int
2452 cmd_cont_common(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv,
2453 int (*t_cont)(mdb_tgt_t *, mdb_tgt_status_t *), const char *name)
2455 mdb_tgt_t *t = mdb.m_target;
2456 mdb_tgt_status_t st;
2457 int sig = 0;
2459 if ((flags & DCMD_ADDRSPEC) || argc > CONT_MAXARGS)
2460 return (DCMD_USAGE);
2462 if (argc > 0) {
2463 if (argv->a_type == MDB_TYPE_STRING) {
2464 if (proc_str2sig(argv->a_un.a_str, &sig) == -1) {
2465 mdb_warn("invalid signal name -- %s\n",
2466 argv->a_un.a_str);
2467 return (DCMD_USAGE);
2469 } else
2470 sig = (int)(intmax_t)argv->a_un.a_val;
2473 (void) mdb_tgt_status(t, &st);
2475 if (st.st_state == MDB_TGT_IDLE && mdb_tgt_run(t, 0, NULL) == -1) {
2476 if (errno != EMDB_TGT)
2477 mdb_warn("failed to create new target");
2478 return (DCMD_ERR);
2481 if (sig != 0 && mdb_tgt_signal(t, sig) == -1) {
2482 mdb_warn("failed to post signal %d", sig);
2483 return (DCMD_ERR);
2486 if (st.st_state == MDB_TGT_IDLE && t_cont == &mdb_tgt_step) {
2487 (void) mdb_tgt_status(t, &st);
2488 return (tgt_status(&st));
2491 if (t_cont(t, &st) == -1) {
2492 if (errno != EMDB_TGT)
2493 mdb_warn("failed to %s target", name);
2494 return (DCMD_ERR);
2497 return (tgt_status(&st));
2500 static int
2501 cmd_step(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2503 int (*func)(mdb_tgt_t *, mdb_tgt_status_t *) = &mdb_tgt_step;
2504 const char *name = "single-step";
2506 if (argc > 0 && argv->a_type == MDB_TYPE_STRING) {
2507 if (strcmp(argv->a_un.a_str, "out") == 0) {
2508 func = &mdb_tgt_step_out;
2509 name = "step (out)";
2510 argv++;
2511 argc--;
2512 } else if (strcmp(argv->a_un.a_str, "over") == 0) {
2513 func = &mdb_tgt_next;
2514 name = "step (over)";
2515 argv++;
2516 argc--;
2520 return (cmd_cont_common(addr, flags, argc, argv, func, name));
2523 static int
2524 cmd_step_out(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2526 return (cmd_cont_common(addr, flags, argc, argv,
2527 &mdb_tgt_step_out, "step (out)"));
2530 static int
2531 cmd_next(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2533 return (cmd_cont_common(addr, flags, argc, argv,
2534 &mdb_tgt_next, "step (over)"));
2537 static int
2538 cmd_cont(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2540 return (cmd_cont_common(addr, flags, argc, argv,
2541 &mdb_tgt_continue, "continue"));
2544 #ifndef _KMDB
2545 /*ARGSUSED*/
2546 static int
2547 cmd_run(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2549 if (flags & DCMD_ADDRSPEC)
2550 return (DCMD_USAGE);
2552 if (mdb_tgt_run(mdb.m_target, argc, argv) == -1) {
2553 if (errno != EMDB_TGT)
2554 mdb_warn("failed to create new target");
2555 return (DCMD_ERR);
2557 return (cmd_cont((uintptr_t)NULL, 0, 0, NULL));
2559 #endif
2562 * To simplify the implementation of :d, :z, and ::delete, we use the sp
2563 * parameter to store the criteria for what to delete. If spec_base is set,
2564 * we delete vespecs with a matching address. If spec_id is set, we delete
2565 * vespecs with a matching id. Otherwise, we delete all vespecs. We bump
2566 * sp->spec_size so the caller can tell how many vespecs were deleted.
2568 static int
2569 ve_delete(mdb_tgt_t *t, mdb_tgt_spec_desc_t *sp, int vid, void *data)
2571 mdb_tgt_spec_desc_t spec;
2572 int status = -1;
2574 if (vid < 0)
2575 return (0); /* skip over target implementation events */
2577 if (sp->spec_base != (uintptr_t)NULL) {
2578 (void) mdb_tgt_vespec_info(t, vid, &spec, NULL, 0);
2579 if (sp->spec_base - spec.spec_base < spec.spec_size)
2580 status = mdb_tgt_vespec_delete(t, vid);
2581 } else if (sp->spec_id == 0) {
2582 (void) mdb_tgt_vespec_info(t, vid, &spec, NULL, 0);
2583 if (!(spec.spec_flags & MDB_TGT_SPEC_STICKY))
2584 status = mdb_tgt_vespec_delete(t, vid);
2585 } else if (sp->spec_id == vid)
2586 status = mdb_tgt_vespec_delete(t, vid);
2588 if (status == 0) {
2589 if (data != NULL)
2590 strfree(data);
2591 sp->spec_size++;
2594 return (0);
2597 static int
2598 ve_delete_spec(mdb_tgt_spec_desc_t *sp)
2600 (void) mdb_tgt_vespec_iter(mdb.m_target,
2601 (mdb_tgt_vespec_f *)ve_delete, sp);
2603 if (sp->spec_size == 0) {
2604 if (sp->spec_id != 0 || sp->spec_base != (uintptr_t)NULL)
2605 mdb_warn("no traced events matched description\n");
2608 return (DCMD_OK);
2611 /*ARGSUSED*/
2612 static int
2613 cmd_zapall(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2615 mdb_tgt_spec_desc_t spec;
2617 if ((flags & DCMD_ADDRSPEC) || argc != 0)
2618 return (DCMD_USAGE);
2620 bzero(&spec, sizeof (spec));
2621 return (ve_delete_spec(&spec));
2624 static int
2625 cmd_delete(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2627 mdb_tgt_spec_desc_t spec;
2629 if (((flags & DCMD_ADDRSPEC) && argc > 0) || argc > 1)
2630 return (DCMD_USAGE);
2632 bzero(&spec, sizeof (spec));
2634 if (flags & DCMD_ADDRSPEC)
2635 spec.spec_base = addr;
2636 else if (argc == 0)
2637 spec.spec_base = mdb_get_dot();
2638 else if (argv->a_type == MDB_TYPE_STRING &&
2639 strcmp(argv->a_un.a_str, "all") != 0)
2640 spec.spec_id = (int)(intmax_t)mdb_strtonum(argv->a_un.a_str, 10);
2641 else if (argv->a_type == MDB_TYPE_IMMEDIATE)
2642 spec.spec_id = (int)(intmax_t)argv->a_un.a_val;
2644 return (ve_delete_spec(&spec));
2647 static int
2648 cmd_write(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2650 mdb_tgt_as_t as;
2651 int rdback = mdb.m_flags & MDB_FL_READBACK;
2652 mdb_tgt_addr_t naddr;
2653 size_t forced_size = 0;
2654 boolean_t opt_p, opt_o, opt_l;
2655 uint64_t val = 0;
2656 int i;
2658 opt_p = opt_o = opt_l = B_FALSE;
2660 i = mdb_getopts(argc, argv,
2661 'p', MDB_OPT_SETBITS, B_TRUE, &opt_p,
2662 'o', MDB_OPT_SETBITS, B_TRUE, &opt_o,
2663 'l', MDB_OPT_UINTPTR_SET, &opt_l, (uintptr_t *)&forced_size, NULL);
2665 if (!(flags & DCMD_ADDRSPEC))
2666 return (DCMD_USAGE);
2668 if (opt_p && opt_o) {
2669 mdb_warn("-o and -p are incompatible\n");
2670 return (DCMD_USAGE);
2673 argc -= i;
2674 argv += i;
2676 if (argc == 0)
2677 return (DCMD_USAGE);
2679 switch (argv[0].a_type) {
2680 case MDB_TYPE_STRING:
2681 val = mdb_strtoull(argv[0].a_un.a_str);
2682 break;
2683 case MDB_TYPE_IMMEDIATE:
2684 val = argv[0].a_un.a_val;
2685 break;
2686 default:
2687 return (DCMD_USAGE);
2690 if (opt_p)
2691 as = MDB_TGT_AS_PHYS;
2692 else if (opt_o)
2693 as = MDB_TGT_AS_FILE;
2694 else
2695 as = MDB_TGT_AS_VIRT;
2697 if (opt_l)
2698 naddr = write_var_uint(as, addr, val, forced_size, rdback);
2699 else
2700 naddr = write_ctf_uint(as, addr, val, rdback);
2702 if (addr == naddr) {
2703 mdb_warn("failed to write %llr at address %#llx", val, addr);
2704 return (DCMD_ERR);
2707 return (DCMD_OK);
2710 void
2711 write_help(void)
2713 mdb_printf(
2714 "-l length force a write with the specified length in bytes\n"
2715 "-o write data to the object file location specified\n"
2716 "-p write data to the physical address specified\n"
2717 "\n"
2718 "Attempts to write the given value to the address provided.\n"
2719 "If -l is not specified, the address must be the position of a\n"
2720 "symbol that is either of integer, pointer, or enum type. The\n"
2721 "type and the size of the symbol are inferred by the CTF found\n"
2722 "in the provided address. The length of the write is guaranteed\n"
2723 "to be the inferred size of the symbol.\n"
2724 "\n"
2725 "If no CTF data exists, or the address provided is not a symbol\n"
2726 "of integer or pointer type, then the write fails. At that point\n"
2727 "the user can force the write by using the '-l' option and\n"
2728 "specifying its length.\n"
2729 "\n"
2730 "Note that forced writes with a length that are bigger than\n"
2731 "the size of the biggest data pointer supported are not allowed."
2732 "\n");
2735 static void
2736 srcexec_file_help(void)
2738 mdb_printf(
2739 "The library of macros delivered with previous versions of Solaris have been\n"
2740 "superseded by the dcmds and walkers provided by MDB. See ::help for\n"
2741 "commands that can be used to list the available dcmds and walkers.\n"
2742 "\n"
2743 "Aliases have been created for several of the more popular macros. To see\n"
2744 "the list of aliased macros, as well as their native MDB equivalents,\n"
2745 "type $M.\n");
2747 #ifdef _KMDB
2748 mdb_printf(
2749 "When invoked, the $< and $<< dcmds will consult the macro alias list. If an\n"
2750 "alias cannot be found, an attempt will be made to locate a data type whose\n"
2751 "name corresponds to the requested macro. If such a type can be found, it\n"
2752 "will be displayed using the ::print dcmd.\n");
2753 #else
2754 mdb_printf(
2755 "When invoked, the $< and $<< dcmds will first attempt to locate a macro with\n"
2756 "the indicated name. If no macro can be found, and if no alias exists for\n"
2757 "this macro, an attempt will be made to locate a data type whose name\n"
2758 "corresponds to the requested macro. If such a type can be found, it will be\n"
2759 "displayed using the ::print dcmd.\n");
2760 #endif
2763 static void
2764 events_help(void)
2766 mdb_printf("Options:\n"
2767 "-a show all events, including internal debugger events\n"
2768 "-v show verbose display, including inactivity reason\n"
2769 "\nOutput Columns:\n"
2770 "ID decimal event specifier id number:\n"
2771 " [ ] event tracing is enabled\n"
2772 " ( ) event tracing is disabled\n"
2773 " < > target is currently stopped on this type of event\n\n"
2774 "S event specifier state:\n"
2775 " - event specifier is idle (not applicable yet)\n"
2776 " + event specifier is active\n"
2777 " * event specifier is armed (target program running)\n"
2778 " ! error occurred while attempting to arm event\n\n"
2779 "TA event specifier flags:\n"
2780 " t event specifier is temporary (delete at next stop)\n"
2781 " T event specifier is sticky (::delete all has no effect)\n"
2782 " d event specifier will be disabled when HT = LM\n"
2783 " D event specifier will be deleted when HT = LM\n"
2784 " s target will automatically stop when HT = LM\n\n"
2785 "HT hit count (number of times event has occurred)\n"
2786 "LM hit limit (limit for autostop, disable, delete)\n");
2789 static void
2790 dump_help(void)
2792 mdb_printf(
2793 "-e adjust for endianness\n"
2794 " (assumes 4-byte words; use -g to change word size)\n"
2795 #ifdef _KMDB
2796 "-f no effect\n"
2797 #else
2798 "-f dump from object file\n"
2799 #endif
2800 "-g n display bytes in groups of n\n"
2801 " (default is 4; n must be a power of 2, divide line width)\n"
2802 "-l n display n bytes\n"
2803 " (default is 1; rounded up to multiple of line width)\n"
2804 "-p dump from physical memory\n"
2805 "-q don't print ASCII\n"
2806 "-r use relative numbering (automatically sets -u)\n"
2807 "-s elide repeated lines\n"
2808 "-t only read from and display contents of specified addresses\n"
2809 " (default is to read and print entire lines)\n"
2810 "-u un-align output\n"
2811 " (default is to align output at paragraph boundary)\n"
2812 "-w n display n 16-byte paragraphs per line\n"
2813 " (default is 1, maximum is 16)\n");
2817 * Table of built-in dcmds associated with the root 'mdb' module. Future
2818 * expansion of this program should be done here, or through the external
2819 * loadable module interface.
2821 const mdb_dcmd_t mdb_dcmd_builtins[] = {
2824 * dcmds common to both mdb and kmdb
2826 { ">", "variable-name", "assign variable", cmd_assign_variable },
2827 { "/", "fmt-list", "format data from virtual as", cmd_print_core },
2828 { "\\", "fmt-list", "format data from physical as", cmd_print_phys },
2829 { "@", "fmt-list", "format data from physical as", cmd_print_phys },
2830 { "=", "fmt-list", "format immediate value", cmd_print_value },
2831 { "$<", "macro-name", "replace input with macro",
2832 cmd_exec_file, srcexec_file_help },
2833 { "$<<", "macro-name", "source macro",
2834 cmd_src_file, srcexec_file_help},
2835 { "$%", NULL, NULL, cmd_quit },
2836 { "$?", NULL, "print status and registers", cmd_notsup },
2837 { "$a", NULL, NULL, cmd_algol },
2838 { "$b", "[-av]", "list traced software events",
2839 cmd_events, events_help },
2840 { "$c", "?[cnt]", "print stack backtrace", cmd_notsup },
2841 { "$C", "?[cnt]", "print stack backtrace", cmd_notsup },
2842 { "$d", NULL, "get/set default output radix", cmd_radix },
2843 { "$D", "?[mode,...]", NULL, cmd_dbmode },
2844 { "$e", NULL, "print listing of global symbols", cmd_globals },
2845 { "$f", NULL, "print listing of source files", cmd_files },
2846 { "$m", "?[name]", "print address space mappings", cmd_mappings },
2847 { "$M", NULL, "list macro aliases", cmd_macalias_list },
2848 { "$P", "[prompt]", "set debugger prompt string", cmd_prompt },
2849 { "$q", NULL, "quit debugger", cmd_quit },
2850 { "$Q", NULL, "quit debugger", cmd_quit },
2851 { "$r", NULL, "print general-purpose registers", cmd_notsup },
2852 { "$s", NULL, "get/set symbol matching distance", cmd_symdist },
2853 { "$v", NULL, "print non-zero variables", cmd_nzvars },
2854 { "$V", "[mode]", "get/set disassembly mode", cmd_dismode },
2855 { "$w", NULL, "get/set output page width", cmd_pgwidth },
2856 { "$W", NULL, "re-open target in write mode", cmd_reopen },
2857 { ":a", ":[cmd...]", "set read access watchpoint", cmd_oldwpr },
2858 { ":b", ":[cmd...]", "breakpoint at the specified address", cmd_oldbp },
2859 { ":d", "?[id|all]", "delete traced software events", cmd_delete },
2860 { ":p", ":[cmd...]", "set execute access watchpoint", cmd_oldwpx },
2861 { ":S", NULL, NULL, cmd_step },
2862 { ":w", ":[cmd...]", "set write access watchpoint", cmd_oldwpw },
2863 { ":z", NULL, "delete all traced software events", cmd_zapall },
2864 { "array", ":[type count] [variable]", "print each array element's "
2865 "address", cmd_array },
2866 { "bp", "?[+/-dDestT] [-c cmd] [-n count] sym ...", "breakpoint at the "
2867 "specified addresses or symbols", cmd_bp, bp_help },
2868 { "dcmds", "[[-n] pattern]",
2869 "list available debugger commands", cmd_dcmds, cmd_dcmds_help },
2870 { "delete", "?[id|all]", "delete traced software events", cmd_delete },
2871 { "dis", "?[-abfw] [-n cnt] [addr]", "disassemble near addr", cmd_dis },
2872 { "disasms", NULL, "list available disassemblers", cmd_disasms },
2873 { "dismode", "[mode]", "get/set disassembly mode", cmd_dismode },
2874 { "dmods", "[-l] [mod]", "list loaded debugger modules", cmd_dmods },
2875 { "dump", "?[-eqrstu] [-f|-p] [-g bytes] [-l bytes] [-w paragraphs]",
2876 "dump memory from specified address", cmd_dump, dump_help },
2877 { "echo", "args ...", "echo arguments", cmd_echo },
2878 { "enum", "?[-ex] enum [name]", "print an enumeration", cmd_enum,
2879 enum_help },
2880 { "eval", "command", "evaluate the specified command", cmd_eval },
2881 { "events", "[-av]", "list traced software events",
2882 cmd_events, events_help },
2883 { "evset", "?[+/-dDestT] [-c cmd] [-n count] id ...",
2884 "set software event specifier attributes", cmd_evset, evset_help },
2885 { "files", "[object]", "print listing of source files", cmd_files },
2886 { "formats", NULL, "list format specifiers", cmd_formats },
2887 { "grep", "?expr", "print dot if expression is true", cmd_grep },
2888 { "head", "-num|-n num", "limit number of elements in pipe", cmd_head,
2889 head_help },
2890 { "help", "[cmd]", "list commands/command help", cmd_help, NULL,
2891 cmd_help_tab },
2892 { "list", "?type member [variable]",
2893 "walk list using member as link pointer", cmd_list, NULL,
2894 mdb_tab_complete_mt },
2895 { "map", "?expr", "print dot after evaluating expression", cmd_map },
2896 { "mappings", "?[name]", "print address space mappings", cmd_mappings },
2897 { "nm", "?[-DPdghnopuvx] [-f format] [-t types] [object]",
2898 "print symbols", cmd_nm, nm_help },
2899 { "nmadd", ":[-fo] [-e end] [-s size] name",
2900 "add name to private symbol table", cmd_nmadd, nmadd_help },
2901 { "nmdel", "name", "remove name from private symbol table", cmd_nmdel },
2902 { "obey", NULL, NULL, cmd_obey },
2903 { "objects", "[-v]", "print load objects information", cmd_objects },
2904 { "offsetof", "type member", "print the offset of a given struct "
2905 "or union member", cmd_offsetof, NULL, mdb_tab_complete_mt },
2906 { "print", "?[-aCdhiLptx] [-c lim] [-l lim] [type] [member|offset ...]",
2907 "print the contents of a data structure", cmd_print, print_help,
2908 cmd_print_tab },
2909 { "printf", "?format type member ...", "print and format the "
2910 "member(s) of a data structure", cmd_printf, printf_help,
2911 cmd_printf_tab },
2912 { "regs", NULL, "print general purpose registers", cmd_notsup },
2913 { "set", "[-wF] [+/-o opt] [-s dist] [-I path] [-L path] [-P prompt]",
2914 "get/set debugger properties", cmd_set },
2915 { "showrev", "[-pv]", "print version information", cmd_showrev },
2916 { "sizeof", "type", "print the size of a type", cmd_sizeof, NULL,
2917 cmd_sizeof_tab },
2918 { "stack", "?[cnt]", "print stack backtrace", cmd_notsup },
2919 { "stackregs", "?", "print stack backtrace and registers",
2920 cmd_notsup },
2921 { "status", NULL, "print summary of current target", cmd_notsup },
2922 { "term", NULL, "display current terminal type", cmd_term },
2923 { "typeset", "[+/-t] var ...", "set variable attributes", cmd_typeset },
2924 { "typedef", "[-c model | -d | -l | -r file | -w file ] [type] [name]",
2925 "create synthetic types", cmd_typedef, cmd_typedef_help },
2926 { "unset", "[name ...]", "unset variables", cmd_unset },
2927 { "vars", "[-npt]", "print listing of variables", cmd_vars },
2928 { "version", NULL, "print debugger version string", cmd_version },
2929 { "vtop", ":[-a as]", "print physical mapping of virtual address",
2930 cmd_vtop },
2931 { "walk", "?name [variable]", "walk data structure", cmd_walk, NULL,
2932 cmd_walk_tab },
2933 { "walkers", "[[-n] pattern]", "list available walkers",
2934 cmd_walkers, cmd_walkers_help },
2935 { "whatis", ":[-aikqv]", "given an address, return information",
2936 cmd_whatis, whatis_help },
2937 { "whence", "[-v] name ...", "show source of walk or dcmd", cmd_which },
2938 { "which", "[-v] name ...", "show source of walk or dcmd", cmd_which },
2939 { "write", "?[-op] [-l len] value",
2940 "write value to the provided memory location", cmd_write,
2941 write_help },
2942 { "xdata", NULL, "print list of external data buffers", cmd_xdata },
2944 #ifdef _KMDB
2946 * dcmds specific to kmdb, or which have kmdb-specific arguments
2948 { "?", "fmt-list", "format data from virtual as", cmd_print_core },
2949 { ":c", NULL, "continue target execution", cmd_cont },
2950 { ":e", NULL, "step target over next instruction", cmd_next },
2951 { ":s", NULL, "single-step target to next instruction", cmd_step },
2952 { ":u", NULL, "step target out of current function", cmd_step_out },
2953 { "cont", NULL, "continue target execution", cmd_cont },
2954 { "load", "[-sd] module", "load debugger module", cmd_load, load_help },
2955 { "next", NULL, "step target over next instruction", cmd_next },
2956 { "quit", "[-u]", "quit debugger", cmd_quit, quit_help },
2957 { "step", "[ over | out ]",
2958 "single-step target to next instruction", cmd_step },
2959 { "unload", "[-d] module", "unload debugger module", cmd_unload,
2960 unload_help },
2961 { "wp", ":[+/-dDelstT] [-rwx] [-pi] [-c cmd] [-n count] [-L size]",
2962 "set a watchpoint at the specified address", cmd_wp, wp_help },
2964 #else
2966 * dcmds specific to mdb, or which have mdb-specific arguments
2968 { "?", "fmt-list", "format data from object file", cmd_print_object },
2969 { "$>", "[file]", "log session to a file", cmd_old_log },
2970 { "$g", "?", "get/set C++ demangling options", cmd_demflags },
2971 { "$G", NULL, "enable/disable C++ demangling support", cmd_demangle },
2972 { "$i", NULL, "print signals that are ignored", cmd_notsup },
2973 { "$l", NULL, "print the representative thread's lwp id", cmd_notsup },
2974 { "$p", ":", "change debugger target context", cmd_context },
2975 { "$x", NULL, "print floating point registers", cmd_notsup },
2976 { "$X", NULL, "print floating point registers", cmd_notsup },
2977 { "$y", NULL, "print floating point registers", cmd_notsup },
2978 { "$Y", NULL, "print floating point registers", cmd_notsup },
2979 { ":A", "?[core|pid]", "attach to process or core file", cmd_notsup },
2980 { ":c", "[SIG]", "continue target execution", cmd_cont },
2981 { ":e", "[SIG]", "step target over next instruction", cmd_next },
2982 { ":i", ":", "ignore signal (delete all matching events)", cmd_notsup },
2983 { ":k", NULL, "forcibly kill and release target", cmd_notsup },
2984 { ":t", "?[+/-dDestT] [-c cmd] [-n count] SIG ...", "stop on delivery "
2985 "of the specified signals", cmd_sigbp, sigbp_help },
2986 { ":r", "[ args ... ]", "run a new target process", cmd_run },
2987 { ":R", NULL, "release the previously attached process", cmd_notsup },
2988 { ":s", "[SIG]", "single-step target to next instruction", cmd_step },
2989 { ":u", "[SIG]", "step target out of current function", cmd_step_out },
2990 { "attach", "?[core|pid]",
2991 "attach to process or core file", cmd_notsup },
2992 { "cat", "[file ...]", "concatenate and display files", cmd_cat },
2993 { "cont", "[SIG]", "continue target execution", cmd_cont },
2994 { "context", ":", "change debugger target context", cmd_context },
2995 { "dem", "name ...", "demangle C++ symbol names", cmd_demstr },
2996 { "fltbp", "?[+/-dDestT] [-c cmd] [-n count] fault ...",
2997 "stop on machine fault", cmd_fltbp, fltbp_help },
2998 { "fpregs", NULL, "print floating point registers", cmd_notsup },
2999 { "kill", NULL, "forcibly kill and release target", cmd_notsup },
3000 { "load", "[-s] module", "load debugger module", cmd_load, load_help },
3001 { "log", "[-d | [-e] file]", "log session to a file", cmd_log },
3002 { "next", "[SIG]", "step target over next instruction", cmd_next },
3003 { "quit", NULL, "quit debugger", cmd_quit },
3004 { "release", NULL,
3005 "release the previously attached process", cmd_notsup },
3006 { "run", "[ args ... ]", "run a new target process", cmd_run },
3007 { "sigbp", "?[+/-dDestT] [-c cmd] [-n count] SIG ...", "stop on "
3008 "delivery of the specified signals", cmd_sigbp, sigbp_help },
3009 { "step", "[ over | out ] [SIG]",
3010 "single-step target to next instruction", cmd_step },
3011 { "sysbp", "?[+/-dDestT] [-io] [-c cmd] [-n count] syscall ...",
3012 "stop on entry or exit from system call", cmd_sysbp, sysbp_help },
3013 { "unload", "module", "unload debugger module", cmd_unload },
3014 { "wp", ":[+/-dDelstT] [-rwx] [-c cmd] [-n count] [-L size]",
3015 "set a watchpoint at the specified address", cmd_wp, wp_help },
3016 #endif
3018 { NULL }