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