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