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