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