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