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