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