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]
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.
36 #include <sys/elf_SPARC.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>
75 #include <kmdb/kmdb_kdi.h>
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
),
89 if (mdb_tgt_awrite(mdb
.m_target
, as
, &n
, sizeof (n
), addr
) == -1)
93 if (mdb_tgt_aread(mdb
.m_target
, as
, &n
, sizeof (n
), addr
) == -1)
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
),
112 if (mdb_tgt_awrite(mdb
.m_target
, as
, &n
, sizeof (n
), addr
) == -1)
116 if (mdb_tgt_aread(mdb
.m_target
, as
, &n
, sizeof (n
), addr
) == -1)
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
),
135 if (mdb_tgt_awrite(mdb
.m_target
, as
, &n
, sizeof (n
), addr
) == -1)
139 if (mdb_tgt_aread(mdb
.m_target
, as
, &n
, sizeof (n
), addr
) == -1)
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
)
154 if (rdback
&& mdb_tgt_aread(mdb
.m_target
, as
, &o
, sizeof (o
),
158 if (mdb_tgt_awrite(mdb
.m_target
, as
, &n
, sizeof (n
), addr
) == -1)
162 if (mdb_tgt_aread(mdb
.m_target
, as
, &n
, sizeof (n
), addr
) == -1)
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
,
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 */
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
);
203 return (write_uint8(as
, addr
, val
, rdback
));
205 return (write_uint16(as
, addr
, val
, rdback
));
207 return (write_uint32(as
, addr
, val
, rdback
));
209 return (write_uint64(as
, addr
, val
, rdback
));
211 mdb_warn("writes of size %u are not supported\n ", size
);
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
)
224 if (mdb_ctf_lookup_by_addr(addr
, &mid
) != 0) {
225 mdb_warn("no CTF data found at this address\n");
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");
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");
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");
250 type_size
= mdb_ctf_type_size(mid
);
252 mdb_warn("CTF data found but size could not be read");
257 return (write_var_uint(as
, addr
, n
, size
, rdback
));
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
,
266 mdb_tgt_addr_t naddr
;
268 int rdback
= mdb
.m_flags
& MDB_FL_READBACK
;
272 mdb_warn("expected value to write following %c\n",
277 switch (argv
->a_un
.a_char
) {
279 write_value
= write_uint8
;
282 write_value
= write_uint16
;
285 write_value
= write_ctf_uint
;
288 write_value
= write_uint32
;
291 write_value
= write_uint64
;
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",
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\"",
308 value
= mdb_nv_get_value(mdb
.m_dot
);
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",
321 mdb
.m_incr
= naddr
- addr
;
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
);
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
);
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
)
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
);
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
,
383 uint64_t args
[2] = { 0, -1ULL }; /* [ value, mask ] */
387 mdb_warn("expected value following %c\n", argv
->a_un
.a_char
);
392 mdb_warn("only value and mask may follow %c\n",
397 switch (argv
->a_un
.a_char
) {
399 match_value
= match_uint16
;
402 match_value
= match_uint32
;
405 match_value
= match_uint64
;
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",
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\"",
422 args
[i
- 1] = mdb_nv_get_value(mdb
.m_dot
);
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
);
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
)
444 if (argv
->a_un
.a_char
!= *s
)
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
;
460 if (DCMD_HDRSPEC(flags
) && (flags
& DCMD_PIPE_OUT
) == 0) {
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")) {
470 } else if (argncmp(argc
, argv
, "ia")) {
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
);
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
);
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
) {
523 naddr
= mdb_fmt_print(mdb
.m_target
, as
, addr
, n
,
525 mdb
.m_incr
= naddr
- addr
;
530 case MDB_TYPE_IMMEDIATE
:
531 n
= argv
->a_un
.a_val
;
534 case MDB_TYPE_STRING
:
535 mdb_iob_puts(mdb
.m_out
, argv
->a_un
.a_str
);
541 mdb
.m_incr
= addr
- oaddr
;
542 mdb_iob_clrflags(mdb
.m_out
, MDB_IOB_INDENT
);
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
));
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
));
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
));
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
));
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];
594 mdb_warn("expected one or more format characters "
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
) {
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
== '-')
614 case MDB_TYPE_IMMEDIATE
:
615 n
= argv
->a_un
.a_val
;
618 case MDB_TYPE_STRING
:
619 mdb_iob_puts(mdb
.m_out
, argv
->a_un
.a_str
);
625 mdb_iob_clrflags(mdb
.m_out
, MDB_IOB_INDENT
);
626 mdb_nv_set_value(mdb
.m_dot
, dot
);
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
);
643 if (argv
->a_type
!= MDB_TYPE_CHAR
) {
644 mdb_warn("improper arguments following '>' operator\n");
648 switch (argv
->a_un
.a_char
) {
650 addr
= *((uchar_t
*)&addr
);
653 addr
= *((ushort_t
*)&addr
);
656 addr
= *((uint_t
*)&addr
);
659 addr
= *((ulong_t
*)&addr
);
662 mdb_warn("%c is not a valid // modifier\n",
672 if (argc
!= 1 || argv
->a_type
!= MDB_TYPE_STRING
) {
673 mdb_warn("expected single variable name following '>'\n");
677 if (strlen(argv
->a_un
.a_str
) >= (size_t)MDB_NV_NAMELEN
) {
678 mdb_warn("variable names may not exceed %d characters\n",
683 if ((p
= strbadid(argv
->a_un
.a_str
)) != NULL
) {
684 mdb_warn("'%c' may not be used in a variable name\n", *p
);
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);
691 mdb_nv_set_value(v
, dot
);
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
);
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) {
713 v
.a_type
= MDB_TYPE_STRING
;
716 rv
= mdb_call_dcmd("print", addr
, flags
, 1, &v
);
725 print_type(const char *name
, uintptr_t addr
, uint_t flags
)
732 if (!(flags
& DCMD_ADDRSPEC
)) {
733 addr
= mdb_get_dot();
734 flags
|= DCMD_ADDRSPEC
;
737 if ((rv
= print_soutype(name
, addr
, flags
)) != DCMD_ERR
)
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) {
748 v
.a_type
= MDB_TYPE_STRING
;
749 v
.a_un
.a_str
= sname
;
751 rv
= mdb_call_dcmd("print", addr
, flags
, 1, &v
);
755 sname
[snamesz
- 2] = 's';
756 rv
= print_soutype(sname
, addr
, flags
);
761 exec_alias(const char *fname
, uintptr_t addr
, uint_t flags
)
766 if ((alias
= mdb_macalias_lookup(fname
)) == NULL
)
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
);
775 rv
= mdb_eval(alias
);
778 return (rv
== -1 ? DCMD_ABORT
: DCMD_OK
);
783 cmd_src_file(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
789 if (argc
!= 1 || argv
->a_type
!= MDB_TYPE_STRING
)
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");
799 if ((fio
= mdb_fdio_create_path(mdb
.m_ipath
, fname
,
800 O_RDONLY
, 0)) != NULL
) {
801 mdb_frame_t
*fp
= mdb
.m_frame
;
804 mdb_iob_stack_push(&fp
->f_istk
, mdb
.m_in
, yylineno
);
805 mdb
.m_in
= mdb_iob_create(fio
, MDB_IOB_RDONLY
);
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
);
822 if ((rv
= exec_alias(fname
, addr
, flags
)) != DCMD_ERR
||
823 (rv
= print_type(fname
, addr
, flags
)) != DCMD_ERR
)
826 mdb_warn("failed to open %s (see ::help '$<')\n", fname
);
831 cmd_exec_file(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
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.
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
);
854 mdb_warn("input stack is empty\n");
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
)
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
);
873 if ((rv
= exec_alias(fname
, addr
, flags
)) != DCMD_ERR
||
874 (rv
= print_type(fname
, addr
, flags
)) != DCMD_ERR
)
877 mdb_warn("failed to open %s (see ::help '$<')\n", fname
);
884 cmd_cat(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
886 int status
= DCMD_OK
;
891 if (flags
& DCMD_ADDRSPEC
)
894 for (; argc
-- != 0; argv
++) {
895 if (argv
->a_type
!= MDB_TYPE_STRING
) {
896 mdb_warn("expected string argument\n");
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
);
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
));
913 if (mdb_iob_write(mdb
.m_out
, buf
, len
) < 0) {
915 mdb_warn("write failed");
922 if (mdb_iob_err(iob
))
923 mdb_warn("error while reading %s", mdb_iob_name(iob
));
925 mdb_iob_destroy(iob
);
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
)
939 if (mdb_eval(argv
->a_un
.a_str
) == -1)
942 if (mdb_get_dot() != 0)
943 mdb_printf("%lr\n", addr
);
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
)
955 if (mdb_eval(argv
->a_un
.a_str
) == -1)
958 mdb_printf("%llr\n", mdb_get_dot());
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");
972 cmd_quit(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
975 uint_t opt_u
= FALSE
;
977 if (mdb_getopts(argc
, argv
,
978 'u', MDB_OPT_SETBITS
, TRUE
, &opt_u
, NULL
) != argc
)
982 if (mdb
.m_flags
& MDB_FL_NOUNLOAD
) {
983 warn("%s\n", mdb_strerror(EMDB_KNOUNLOAD
));
987 kmdb_kdi_set_unload_request();
991 longjmp(mdb
.m_frame
->f_pcb
, MDB_ERR_QUIT
);
1001 "-u unload the debugger (if not loaded at boot)\n");
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
;
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)) {
1024 mdb_printf("%#llr>%s\n",
1025 mdb_nv_get_value(v
), mdb_nv_get_name(v
));
1027 mdb_printf("%s = %llr\n",
1028 mdb_nv_get_name(v
), mdb_nv_get_value(v
));
1038 cmd_nzvars(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
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
);
1058 cmd_radix(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
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");
1068 mdb
.m_radix
= (int)addr
;
1071 mdb_iob_printf(mdb
.m_out
, "radix = %d base ten\n", mdb
.m_radix
);
1077 cmd_symdist(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
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");
1093 cmd_pgwidth(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
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
);
1107 cmd_reopen(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
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");
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
);
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
);
1141 cmd_unset(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
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",
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",
1159 mdb_nv_remove(&mdb
.m_nv
, v
);
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
;
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
);
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.
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");
1201 mdb_printf("%s: no log is active\n", mdb
.m_pname
);
1206 * If the -d option was specified, pop the log i/o object off the
1207 * i/o stack of stdin, stdout, and stderr.
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
;
1216 mdb_warn("logging is already disabled\n");
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
);
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
;
1258 mdb_warn("no log file has been selected\n");
1263 cmd_old_log(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
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
));
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
,
1282 'd', MDB_OPT_SETBITS
, MDB_MOD_DEFER
, &mode
,
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
,
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)
1308 "-d defer load until next continue\n"
1310 "-s load module silently\n");
1315 cmd_unload(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
1320 i
= mdb_getopts(argc
, argv
,
1322 'd', MDB_OPT_SETBITS
, MDB_MOD_DEFER
, &mode
,
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
);
1345 "-d defer unload until next continue\n");
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
);
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
)
1360 } else if (flags
& DCMD_ADDRSPEC
)
1363 mdb_printf("debugging mode = 0x%04x\n", mdb
.m_debug
);
1369 cmd_version(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
1372 mdb_printf("\r%s (DEBUG)\n", mdb_conf_version());
1374 mdb_printf("\r%s\n", mdb_conf_version());
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");
1386 mdb_printf("No adb here\n");
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");
1397 mdb_printf("No Language H here\n");
1403 print_global(void *data
, const GElf_Sym
*sym
, const char *name
,
1404 const mdb_syminfo_t
*sip
, const char *obj
)
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
);
1412 mdb_printf("%s(%llr):\t?\n", name
, sym
->st_value
);
1419 cmd_globals(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
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
);
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
);
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
);
1458 cmd_files(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
1461 const char *obj
= MDB_TGT_OBJ_EVERY
;
1463 if ((flags
& DCMD_ADDRSPEC
) || argc
> 1)
1464 return (DCMD_USAGE
);
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
);
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)
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 ]");
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
);
1510 cmd_mappings(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
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");
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
);
1530 m
= mdb_tgt_addr_to_map(mdb
.m_target
, argv
->a_un
.a_val
);
1533 mdb_warn("failed to obtain mapping");
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");
1544 whatis_map_callback(void *wp
, const mdb_map_t
*map
, const char *name
)
1546 mdb_whatis_t
*w
= wp
;
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
);
1560 whatis_run_mappings(mdb_whatis_t
*w
, void *ignored
)
1562 (void) mdb_tgt_mapping_iter(mdb
.m_target
, whatis_map_callback
, w
);
1568 objects_printversion(void *ignored
, const mdb_map_t
*map
, const char *name
)
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
);
1583 cmd_objects(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
1585 uint_t opt_v
= FALSE
;
1588 if ((flags
& DCMD_ADDRSPEC
) || mdb_getopts(argc
, argv
,
1589 'v', MDB_OPT_SETBITS
, TRUE
, &opt_v
, NULL
) != argc
)
1590 return (DCMD_USAGE
);
1593 cb
= objects_printversion
;
1594 mdb_printf("%<u>%-28s %s%</u>\n", "NAME", "VERSION");
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");
1611 showrev_addversion(void *vers_nv
, const mdb_map_t
*ignored
, const char *object
)
1614 const char *version
= NULL
;
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
,
1636 showrev_ispatch(const char *s
)
1642 s
++; /* skip T for T-patch */
1644 for (; *s
!= '\0'; s
++) {
1645 if ((*s
< '0' || *s
> '9') && *s
!= '-')
1654 showrev_printobject(mdb_var_t
*v
, void *ignored
)
1656 mdb_printf("%s ", MDB_NV_COOKIE(v
));
1661 showrev_printversion(mdb_var_t
*v
, void *showall
)
1663 const char *version
= mdb_nv_get_name(v
);
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);
1682 * Display version information for each object in the system.
1683 * Print information about patches only, unless showall is TRUE.
1686 showrev_objectversions(int showall
)
1690 (void) mdb_nv_create(&vers_nv
, UM_SLEEP
| UM_GC
);
1691 if (mdb_tgt_object_iter(mdb
.m_target
, showrev_addversion
,
1693 mdb_warn("failed to iterate over objects");
1697 mdb_nv_sort_iter(&vers_nv
, showrev_printversion
,
1698 (void *)(uintptr_t)showall
, UM_SLEEP
| UM_GC
);
1703 * Display information similar to what showrev(8) displays when invoked
1704 * with no arguments.
1707 showrev_sysinfo(void)
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
);
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
);
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
);
1748 return (showrev_objectversions(opt_v
));
1750 return (showrev_sysinfo());
1755 dis_str2addr(const char *s
, uintptr_t *addr
)
1759 if (s
[0] >= '0' && s
[0] <= '9') {
1760 *addr
= (uintptr_t)mdb_strtoull(s
);
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
);
1770 *addr
= (uintptr_t)sym
.st_value
;
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
;
1782 mdb_tgt_status_t st
;
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.
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
))
1816 addr
= argv
[i
].a_un
.a_val
;
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
;
1841 * Window-mode doesn't make sense in a loop.
1843 if (flags
& DCMD_LOOP
)
1847 * If -n was explicit, limit output to n instructions;
1848 * otherwise set n to some reasonable default
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
)
1862 as
= MDB_TGT_AS_FILE
;
1864 as
= MDB_TGT_AS_VIRT
;
1866 if (opt_w
== FALSE
) {
1868 while ((eaddr
== 0 && n
-- != 0) || (addr
< eaddr
)) {
1869 naddr
= mdb_dis_ins2str(dis
, tgt
, as
,
1870 buf
, sizeof (buf
), addr
);
1874 mdb_printf("%-#32p%8T%s\n", addr
, buf
);
1876 mdb_printf("%-#?p %-#32a%8T%s\n",
1879 mdb_printf("%-#32a%8T%s\n", addr
, buf
);
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
);
1892 mdb_printf("%-#32p%8T%s\n", oaddr
, buf
);
1894 mdb_printf("%-#?p %-#32a%8T%s\n",
1897 mdb_printf("%-#32a%8T%s\n", oaddr
, buf
);
1900 if ((naddr
= mdb_dis_ins2str(dis
, tgt
, as
,
1901 buf
, sizeof (buf
), addr
)) == addr
)
1907 mdb_printf("%-#32p%8T%s%", addr
, buf
);
1909 mdb_printf("%-#?p %-#32a%8T%s", addr
, addr
, buf
);
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
);
1920 mdb_printf("%-#32p%8T%s\n", addr
, buf
);
1922 mdb_printf("%-#?p %-#32a%8T%s\n",
1925 mdb_printf("%-#32a%8T%s\n", addr
, buf
);
1935 walk_step(uintptr_t addr
, const void *data
, void *private)
1937 mdb_printf("%#lr\n", addr
);
1942 cmd_walk(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
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
);
1951 const char *name
= argv
[1].a_un
.a_str
;
1952 mdb_var_t
*v
= mdb_nv_lookup(&mdb
.m_nv
, name
);
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 "
1963 return (DCMD_ABORT
);
1966 if (v
== NULL
&& (v
= mdb_nv_insert(&mdb
.m_nv
,
1967 name
, NULL
, 0, 0)) == NULL
)
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
);
1982 status
= mdb_walk(argv
->a_un
.a_str
, walk_step
, NULL
);
1985 mdb_warn("failed to perform walk");
1993 cmd_walk_tab(mdb_tab_cookie_t
*mcp
, uint_t flags
, int argc
,
1994 const mdb_arg_t
*argv
)
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
));
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
));
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
));
2028 cmd_dump(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
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
;
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
);
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
)
2071 dflags
|= MDB_DUMP_GROUP(group
) | MDB_DUMP_WIDTH(width
);
2073 error
= mdb_dump64(mdb_get_dot(), length
, dflags
,
2074 mdb_partial_pread
, NULL
);
2076 error
= mdb_dumpptr(addr
, length
, dflags
,
2077 mdb_partial_xread
, (void *)mdb_tgt_fread
);
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
);
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
);
2096 mdb_printf("%llr ", argv
->a_un
.a_val
);
2105 cmd_head(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
2111 if (!flags
& DCMD_PIPE
)
2112 return (DCMD_USAGE
);
2114 if (argc
== 1 || argc
== 2) {
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;
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');
2136 return (DCMD_USAGE
);
2138 } else if (argc
!= 0) {
2139 return (DCMD_USAGE
);
2144 if (p
.pipe_data
== NULL
)
2146 p
.pipe_len
= MIN(p
.pipe_len
, cnt
);
2148 if (flags
& DCMD_PIPE_OUT
) {
2151 while (p
.pipe_len
-- > 0)
2152 mdb_printf("%lx\n", *p
.pipe_data
++);
2163 "-num pass only the first `num' elements in the pipe.\n"
2164 "\n%<b>Note:%</b> `num' is a decimal number.\n");
2168 cmd_typeset(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
2170 int add_tag
= 0, del_tag
= 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] == '-')
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
)
2196 if (argv
->a_un
.a_str
[0] == '-' || argv
->a_un
.a_str
[0] == '+') {
2197 mdb_warn("ignored bad option -- %s\n",
2202 if ((p
= strbadid(argv
->a_un
.a_str
)) != NULL
) {
2203 mdb_warn("'%c' may not be used in a variable "
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
,
2211 } else if (flags
& DCMD_ADDRSPEC
)
2212 mdb_nv_set_value(v
, addr
);
2216 v
->v_flags
|= MDB_NV_TAGGED
;
2218 v
->v_flags
&= ~MDB_NV_TAGGED
;
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)
2242 cmd_prompt(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
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
);
2258 cmd_term(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
2260 mdb_printf("%s\n", mdb
.m_termtype
);
2267 cmd_vtop(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
2270 mdb_tgt_as_t as
= MDB_TGT_AS_VIRT
;
2272 if (mdb_getopts(argc
, argv
, 'a', MDB_OPT_UINTPTR
, (uintptr_t *)&as
,
2274 return (DCMD_USAGE
);
2276 if (mdb_tgt_vtop(mdb
.m_target
, as
, addr
, &pa
) == -1) {
2277 mdb_warn("failed to get physical mapping");
2281 if (flags
& DCMD_PIPE_OUT
)
2282 mdb_printf("%llr\n", pa
);
2284 mdb_printf("virtual %lr mapped to physical %llr\n", addr
, pa
);
2288 #define EVENTS_OPT_A 0x1 /* ::events -a (show all events) */
2289 #define EVENTS_OPT_V 0x2 /* ::events -v (verbose display) */
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
);
2303 static const char dash20
[] = "--------------------";
2304 mdb_printf("----- - -- -- -- %s%s --%s\n", dash20
, dash20
, dash20
);
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];
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
);
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
);
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
));
2370 cmd_events(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
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");
2384 mdb_printf(" ID S TA HT LM %-40s %-21s\n",
2385 "Description", "Action");
2389 return (mdb_tgt_vespec_iter(mdb
.m_target
, print_event
,
2390 (void *)(uintptr_t)opts
));
2394 tgt_status(const mdb_tgt_status_t
*tsp
)
2399 if (tsp
->st_flags
& MDB_TGT_BUSY
)
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";
2407 format
= "target stopped at %a:\n";
2408 mdb_warn(format
, tsp
->st_pc
, buf
);
2411 switch (tsp
->st_state
) {
2413 mdb_warn("target is idle\n");
2415 case MDB_TGT_RUNNING
:
2416 if (tsp
->st_flags
& MDB_TGT_DSTOP
)
2417 mdb_warn("target is running, stop directive pending\n");
2419 mdb_warn("target is running\n");
2421 case MDB_TGT_STOPPED
:
2422 if (tsp
->st_pc
== 0)
2423 mdb_warn("target is stopped\n");
2425 case MDB_TGT_UNDEAD
:
2426 mdb_warn("target has terminated\n");
2429 mdb_warn("target is a core dump\n");
2432 mdb_warn("target is no longer under debugger control\n");
2436 mdb_set_dot(tsp
->st_pc
);
2441 * mdb continue/step commands take an optional signal argument, but the
2442 * corresponding kmdb versions don't.
2445 #define CONT_MAXARGS 0 /* no optional SIG argument */
2447 #define CONT_MAXARGS 1
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
;
2459 if ((flags
& DCMD_ADDRSPEC
) || argc
> CONT_MAXARGS
)
2460 return (DCMD_USAGE
);
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",
2467 return (DCMD_USAGE
);
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");
2481 if (sig
!= 0 && mdb_tgt_signal(t
, sig
) == -1) {
2482 mdb_warn("failed to post signal %d", sig
);
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
);
2497 return (tgt_status(&st
));
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)";
2512 } else if (strcmp(argv
->a_un
.a_str
, "over") == 0) {
2513 func
= &mdb_tgt_next
;
2514 name
= "step (over)";
2520 return (cmd_cont_common(addr
, flags
, argc
, argv
, func
, name
));
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)"));
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)"));
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"));
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");
2557 return (cmd_cont((uintptr_t)NULL
, 0, 0, NULL
));
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.
2569 ve_delete(mdb_tgt_t
*t
, mdb_tgt_spec_desc_t
*sp
, int vid
, void *data
)
2571 mdb_tgt_spec_desc_t spec
;
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
);
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");
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
));
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
;
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
));
2648 cmd_write(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
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
;
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
);
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
);
2683 case MDB_TYPE_IMMEDIATE
:
2684 val
= argv
[0].a_un
.a_val
;
2687 return (DCMD_USAGE
);
2691 as
= MDB_TGT_AS_PHYS
;
2693 as
= MDB_TGT_AS_FILE
;
2695 as
= MDB_TGT_AS_VIRT
;
2698 naddr
= write_var_uint(as
, addr
, val
, forced_size
, rdback
);
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
);
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"
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"
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"
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."
2736 srcexec_file_help(void)
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"
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"
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");
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");
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");
2793 "-e adjust for endianness\n"
2794 " (assumes 4-byte words; use -g to change word size)\n"
2798 "-f dump from object file\n"
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
,
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
,
2890 { "help", "[cmd]", "list commands/command help", cmd_help
, NULL
,
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
,
2909 { "printf", "?format type member ...", "print and format the "
2910 "member(s) of a data structure", cmd_printf
, printf_help
,
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
,
2918 { "stack", "?[cnt]", "print stack backtrace", cmd_notsup
},
2919 { "stackregs", "?", "print stack backtrace and registers",
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",
2931 { "walk", "?name [variable]", "walk data structure", cmd_walk
, NULL
,
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
,
2942 { "xdata", NULL
, "print list of external data buffers", cmd_xdata
},
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
,
2961 { "wp", ":[+/-dDelstT] [-rwx] [-pi] [-c cmd] [-n count] [-L size]",
2962 "set a watchpoint at the specified address", cmd_wp
, wp_help
},
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
},
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
},