1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/elf.h> 28 #include <sys/elf_SPARC.h> 29 30 #include <libproc.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <fcntl.h> 34 #include <errno.h> 35 #include <alloca.h> 36 #include <libctf.h> 37 #include <ctype.h> 38 39 #include <mdb/mdb_string.h> 40 #include <mdb/mdb_argvec.h> 41 #include <mdb/mdb_nv.h> 42 #include <mdb/mdb_fmt.h> 43 #include <mdb/mdb_target.h> 44 #include <mdb/mdb_err.h> 45 #include <mdb/mdb_debug.h> 46 #include <mdb/mdb_conf.h> 47 #include <mdb/mdb_module.h> 48 #include <mdb/mdb_modapi.h> 49 #include <mdb/mdb_stdlib.h> 50 #include <mdb/mdb_lex.h> 51 #include <mdb/mdb_io_impl.h> 52 #include <mdb/mdb_help.h> 53 #include <mdb/mdb_disasm.h> 54 #include <mdb/mdb_frame.h> 55 #include <mdb/mdb_evset.h> 56 #include <mdb/mdb_print.h> 57 #include <mdb/mdb_nm.h> 58 #include <mdb/mdb_set.h> 59 #include <mdb/mdb_demangle.h> 60 #include <mdb/mdb_ctf.h> 61 #include <mdb/mdb_whatis.h> 62 #include <mdb/mdb_whatis_impl.h> 63 #include <mdb/mdb_macalias.h> 64 #ifdef _KMDB 65 #include <kmdb/kmdb_kdi.h> 66 #endif 67 #include <mdb/mdb.h> 68 69 #ifdef __sparc 70 #define SETHI_MASK 0xc1c00000 71 #define SETHI_VALUE 0x01000000 72 73 #define IS_SETHI(machcode) (((machcode) & SETHI_MASK) == SETHI_VALUE) 74 75 #define OP(machcode) ((machcode) >> 30) 76 #define OP3(machcode) (((machcode) >> 19) & 0x3f) 77 #define RD(machcode) (((machcode) >> 25) & 0x1f) 78 #define RS1(machcode) (((machcode) >> 14) & 0x1f) 79 #define I(machcode) (((machcode) >> 13) & 0x01) 80 81 #define IMM13(machcode) ((machcode) & 0x1fff) 82 #define IMM22(machcode) ((machcode) & 0x3fffff) 83 84 #define OP_ARITH_MEM_MASK 0x2 85 #define OP_ARITH 0x2 86 #define OP_MEM 0x3 87 88 #define OP3_CC_MASK 0x10 89 #define OP3_COMPLEX_MASK 0x20 90 91 #define OP3_ADD 0x00 92 #define OP3_OR 0x02 93 #define OP3_XOR 0x03 94 95 #ifndef R_O7 96 #define R_O7 0xf 97 #endif 98 #endif /* __sparc */ 99 100 static mdb_tgt_addr_t 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 static const char * 1410 map_name(const mdb_map_t *map, const char *name) 1411 { 1412 if (map->map_flags & MDB_TGT_MAP_HEAP) 1413 return ("[ heap ]"); 1414 if (name != NULL && name[0] != 0) 1415 return (name); 1416 1417 if (map->map_flags & MDB_TGT_MAP_SHMEM) 1418 return ("[ shmem ]"); 1419 if (map->map_flags & MDB_TGT_MAP_STACK) 1420 return ("[ stack ]"); 1421 if (map->map_flags & MDB_TGT_MAP_ANON) 1422 return ("[ anon ]"); 1423 if (map->map_name != NULL) 1424 return (map->map_name); 1425 return ("[ unknown ]"); 1426 } 1427 1428 /*ARGSUSED*/ 1429 static int 1430 print_map(void *ignored, const mdb_map_t *map, const char *name) 1431 { 1432 name = map_name(map, name); 1433 1434 mdb_printf("%?p %?p %?lx %s\n", map->map_base, 1435 map->map_base + map->map_size, map->map_size, name); 1436 return (0); 1437 } 1438 1439 static int 1440 cmd_mappings(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1441 { 1442 const mdb_map_t *m; 1443 1444 if (argc > 1 || (argc != 0 && (flags & DCMD_ADDRSPEC))) 1445 return (DCMD_USAGE); 1446 1447 mdb_printf("%<u>%?s %?s %?s %s%</u>\n", 1448 "BASE", "LIMIT", "SIZE", "NAME"); 1449 1450 if (flags & DCMD_ADDRSPEC) { 1451 if ((m = mdb_tgt_addr_to_map(mdb.m_target, addr)) == NULL) 1452 mdb_warn("failed to obtain mapping"); 1453 else 1454 (void) print_map(NULL, m, NULL); 1455 1456 } else if (argc != 0) { 1457 if (argv->a_type == MDB_TYPE_STRING) 1458 m = mdb_tgt_name_to_map(mdb.m_target, argv->a_un.a_str); 1459 else 1460 m = mdb_tgt_addr_to_map(mdb.m_target, argv->a_un.a_val); 1461 1462 if (m == NULL) 1463 mdb_warn("failed to obtain mapping"); 1464 else 1465 (void) print_map(NULL, m, NULL); 1466 1467 } else if (mdb_tgt_mapping_iter(mdb.m_target, print_map, NULL) == -1) 1468 mdb_warn("failed to iterate over mappings"); 1469 1470 return (DCMD_OK); 1471 } 1472 1473 static int 1474 whatis_map_callback(void *wp, const mdb_map_t *map, const char *name) 1475 { 1476 mdb_whatis_t *w = wp; 1477 uintptr_t cur; 1478 1479 name = map_name(map, name); 1480 1481 while (mdb_whatis_match(w, map->map_base, map->map_size, &cur)) 1482 mdb_whatis_report_address(w, cur, "in %s [%p,%p)\n", 1483 name, map->map_base, map->map_base + map->map_size); 1484 1485 return (0); 1486 } 1487 1488 /*ARGSUSED*/ 1489 int 1490 whatis_run_mappings(mdb_whatis_t *w, void *ignored) 1491 { 1492 (void) mdb_tgt_mapping_iter(mdb.m_target, whatis_map_callback, w); 1493 return (0); 1494 } 1495 1496 /*ARGSUSED*/ 1497 static int 1498 objects_printversion(void *ignored, const mdb_map_t *map, const char *name) 1499 { 1500 ctf_file_t *ctfp; 1501 const char *version; 1502 1503 ctfp = mdb_tgt_name_to_ctf(mdb.m_target, name); 1504 if (ctfp == NULL || (version = ctf_label_topmost(ctfp)) == NULL) 1505 version = "Unknown"; 1506 1507 mdb_printf("%-28s %s\n", name, version); 1508 return (0); 1509 } 1510 1511 /*ARGSUSED*/ 1512 static int 1513 cmd_objects(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1514 { 1515 uint_t opt_v = FALSE; 1516 mdb_tgt_map_f *cb; 1517 1518 if ((flags & DCMD_ADDRSPEC) || mdb_getopts(argc, argv, 1519 'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc) 1520 return (DCMD_USAGE); 1521 1522 if (opt_v) { 1523 cb = objects_printversion; 1524 mdb_printf("%<u>%-28s %s%</u>\n", "NAME", "VERSION"); 1525 } else { 1526 cb = print_map; 1527 mdb_printf("%<u>%?s %?s %?s %s%</u>\n", 1528 "BASE", "LIMIT", "SIZE", "NAME"); 1529 } 1530 1531 if (mdb_tgt_object_iter(mdb.m_target, cb, NULL) == -1) { 1532 mdb_warn("failed to iterate over objects"); 1533 return (DCMD_ERR); 1534 } 1535 1536 return (DCMD_OK); 1537 } 1538 1539 /*ARGSUSED*/ 1540 static int 1541 showrev_addversion(void *vers_nv, const mdb_map_t *ignored, const char *object) 1542 { 1543 ctf_file_t *ctfp; 1544 const char *version = NULL; 1545 char *objname; 1546 1547 objname = mdb_alloc(strlen(object) + 1, UM_SLEEP | UM_GC); 1548 (void) strcpy(objname, object); 1549 1550 if ((ctfp = mdb_tgt_name_to_ctf(mdb.m_target, objname)) != NULL) 1551 version = ctf_label_topmost(ctfp); 1552 1553 /* 1554 * Not all objects have CTF and label data, so set version to "Unknown". 1555 */ 1556 if (version == NULL) 1557 version = "Unknown"; 1558 1559 /* 1560 * The hash table implementation in OVERLOAD mode limits the version 1561 * name to 31 characters because we cannot specify an external name. 1562 * The full version name is available via the ::objects dcmd if needed. 1563 */ 1564 (void) mdb_nv_insert(vers_nv, version, NULL, (uintptr_t)objname, 1565 MDB_NV_OVERLOAD); 1566 1567 return (0); 1568 } 1569 1570 static int 1571 showrev_ispatch(const char *s) 1572 { 1573 if (s == NULL) 1574 return (0); 1575 1576 if (*s == 'T') 1577 s++; /* skip T for T-patch */ 1578 1579 for (; *s != '\0'; s++) { 1580 if ((*s < '0' || *s > '9') && *s != '-') 1581 return (0); 1582 } 1583 1584 return (1); 1585 } 1586 1587 /*ARGSUSED*/ 1588 static int 1589 showrev_printobject(mdb_var_t *v, void *ignored) 1590 { 1591 mdb_printf("%s ", MDB_NV_COOKIE(v)); 1592 return (0); 1593 } 1594 1595 static int 1596 showrev_printversion(mdb_var_t *v, void *showall) 1597 { 1598 const char *version = mdb_nv_get_name(v); 1599 int patch; 1600 1601 patch = showrev_ispatch(version); 1602 if (patch || (uintptr_t)showall) { 1603 mdb_printf("%s: %s Objects: ", 1604 (patch ? "Patch" : "Version"), version); 1605 (void) mdb_inc_indent(2); 1606 1607 mdb_nv_defn_iter(v, showrev_printobject, NULL); 1608 1609 (void) mdb_dec_indent(2); 1610 mdb_printf("\n"); 1611 } 1612 1613 return (0); 1614 } 1615 1616 /* 1617 * Display version information for each object in the system. 1618 * Print information about patches only, unless showall is TRUE. 1619 */ 1620 static int 1621 showrev_objectversions(int showall) 1622 { 1623 mdb_nv_t vers_nv; 1624 1625 (void) mdb_nv_create(&vers_nv, UM_SLEEP | UM_GC); 1626 if (mdb_tgt_object_iter(mdb.m_target, showrev_addversion, 1627 &vers_nv) == -1) { 1628 mdb_warn("failed to iterate over objects"); 1629 return (DCMD_ERR); 1630 } 1631 1632 mdb_nv_sort_iter(&vers_nv, showrev_printversion, 1633 (void *)(uintptr_t)showall, UM_SLEEP | UM_GC); 1634 return (DCMD_OK); 1635 } 1636 1637 /* 1638 * Display information similar to what showrev(1M) displays when invoked 1639 * with no arguments. 1640 */ 1641 static int 1642 showrev_sysinfo(void) 1643 { 1644 const char *s; 1645 int rc; 1646 struct utsname u; 1647 1648 if ((rc = mdb_tgt_uname(mdb.m_target, &u)) != -1) { 1649 mdb_printf("Hostname: %s\n", u.nodename); 1650 mdb_printf("Release: %s\n", u.release); 1651 mdb_printf("Kernel architecture: %s\n", u.machine); 1652 } 1653 1654 /* 1655 * Match the order of the showrev(1M) output and put "Application 1656 * architecture" before "Kernel version" 1657 */ 1658 if ((s = mdb_tgt_isa(mdb.m_target)) != NULL) 1659 mdb_printf("Application architecture: %s\n", s); 1660 1661 if (rc != -1) 1662 mdb_printf("Kernel version: %s %s %s %s\n", 1663 u.sysname, u.release, u.machine, u.version); 1664 1665 if ((s = mdb_tgt_platform(mdb.m_target)) != NULL) 1666 mdb_printf("Platform: %s\n", s); 1667 1668 return (DCMD_OK); 1669 } 1670 1671 /*ARGSUSED*/ 1672 static int 1673 cmd_showrev(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1674 { 1675 uint_t opt_p = FALSE, opt_v = FALSE; 1676 1677 if ((flags & DCMD_ADDRSPEC) || mdb_getopts(argc, argv, 1678 'p', MDB_OPT_SETBITS, TRUE, &opt_p, 1679 'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc) 1680 return (DCMD_USAGE); 1681 1682 if (opt_p || opt_v) 1683 return (showrev_objectversions(opt_v)); 1684 else 1685 return (showrev_sysinfo()); 1686 } 1687 1688 #ifdef __sparc 1689 static void 1690 findsym_output(uintptr_t *symlist, uintptr_t value, uintptr_t location) 1691 { 1692 uintptr_t *symbolp; 1693 1694 for (symbolp = symlist; *symbolp; symbolp++) 1695 if (value == *symbolp) 1696 mdb_printf("found %a at %a\n", value, location); 1697 } 1698 1699 /*ARGSUSED*/ 1700 static int 1701 findsym_cb(void *data, const GElf_Sym *sym, const char *name, 1702 const mdb_syminfo_t *sip, const char *obj) 1703 { 1704 uint32_t *text; 1705 int len; 1706 int i; 1707 int j; 1708 uint8_t rd; 1709 uintptr_t value; 1710 int32_t imm13; 1711 uint8_t op; 1712 uint8_t op3; 1713 uintptr_t *symlist = data; 1714 size_t size = sym->st_size; 1715 1716 /* 1717 * if the size of the symbol is 0, then this symbol must be for an 1718 * alternate entry point or just some global label. We will, 1719 * therefore, get back to the text that follows this symbol in 1720 * some other symbol 1721 */ 1722 if (size == 0) 1723 return (0); 1724 1725 if (sym->st_shndx == SHN_UNDEF) 1726 return (0); 1727 1728 text = alloca(size); 1729 1730 if (mdb_vread(text, size, sym->st_value) == -1) { 1731 mdb_warn("failed to read text for %s", name); 1732 return (0); 1733 } 1734 1735 len = size / 4; 1736 for (i = 0; i < len; i++) { 1737 if (!IS_SETHI(text[i])) 1738 continue; 1739 1740 rd = RD(text[i]); 1741 value = IMM22(text[i]) << 10; 1742 1743 /* 1744 * see if we already have a match with just the sethi 1745 */ 1746 findsym_output(symlist, value, sym->st_value + i * 4); 1747 1748 /* 1749 * search from the sethi on until we hit a relevant instr 1750 */ 1751 for (j = i + 1; j < len; j++) { 1752 if ((op = OP(text[j])) & OP_ARITH_MEM_MASK) { 1753 op3 = OP3(text[j]); 1754 1755 if (RS1(text[j]) != rd) 1756 goto instr_end; 1757 1758 /* 1759 * This is a simple tool; we only deal 1760 * with operations which take immediates 1761 */ 1762 if (I(text[j]) == 0) 1763 goto instr_end; 1764 1765 /* 1766 * sign extend the immediate value 1767 */ 1768 imm13 = IMM13(text[j]); 1769 imm13 <<= 19; 1770 imm13 >>= 19; 1771 1772 if (op == OP_ARITH) { 1773 /* arithmetic operations */ 1774 if (op3 & OP3_COMPLEX_MASK) 1775 goto instr_end; 1776 1777 switch (op3 & ~OP3_CC_MASK) { 1778 case OP3_OR: 1779 value |= imm13; 1780 break; 1781 case OP3_ADD: 1782 value += imm13; 1783 break; 1784 case OP3_XOR: 1785 value ^= imm13; 1786 break; 1787 default: 1788 goto instr_end; 1789 } 1790 } else { 1791 /* loads and stores */ 1792 /* op3 == OP_MEM */ 1793 1794 value += imm13; 1795 } 1796 1797 findsym_output(symlist, value, 1798 sym->st_value + j * 4); 1799 instr_end: 1800 /* 1801 * if we're clobbering rd, break 1802 */ 1803 if (RD(text[j]) == rd) 1804 break; 1805 } else if (IS_SETHI(text[j])) { 1806 if (RD(text[j]) == rd) 1807 break; 1808 } else if (OP(text[j]) == 1) { 1809 /* 1810 * see if a call clobbers an %o or %g 1811 */ 1812 if (rd <= R_O7) 1813 break; 1814 } 1815 } 1816 } 1817 1818 return (0); 1819 } 1820 1821 static int 1822 cmd_findsym(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1823 { 1824 uintptr_t *symlist; 1825 uint_t optg = FALSE; 1826 uint_t type; 1827 int len, i; 1828 1829 i = mdb_getopts(argc, argv, 'g', MDB_OPT_SETBITS, TRUE, &optg, NULL); 1830 1831 argc -= i; 1832 argv += i; 1833 1834 len = argc + ((flags & DCMD_ADDRSPEC) ? 1 : 0) + 1; 1835 1836 if (len <= 1) 1837 return (DCMD_USAGE); 1838 1839 /* 1840 * Set up a NULL-terminated symbol list, and then iterate over the 1841 * symbol table, scanning each function for references to these symbols. 1842 */ 1843 symlist = mdb_alloc(len * sizeof (uintptr_t), UM_SLEEP | UM_GC); 1844 len = 0; 1845 1846 for (i = 0; i < argc; i++, argv++) { 1847 const char *str = argv->a_un.a_str; 1848 uintptr_t value; 1849 GElf_Sym sym; 1850 1851 if (argv->a_type == MDB_TYPE_STRING) { 1852 if (strchr("+-", str[0]) != NULL) 1853 return (DCMD_USAGE); 1854 else if (str[0] >= '0' && str[0] <= '9') 1855 value = mdb_strtoull(str); 1856 else if (mdb_lookup_by_name(str, &sym) != 0) { 1857 mdb_warn("symbol '%s' not found", str); 1858 return (DCMD_USAGE); 1859 } else 1860 value = sym.st_value; 1861 } else 1862 value = argv[i].a_un.a_val; 1863 1864 if (value != NULL) 1865 symlist[len++] = value; 1866 } 1867 1868 if (flags & DCMD_ADDRSPEC) 1869 symlist[len++] = addr; 1870 1871 symlist[len] = NULL; 1872 1873 if (optg) 1874 type = MDB_TGT_BIND_GLOBAL | MDB_TGT_TYPE_FUNC; 1875 else 1876 type = MDB_TGT_BIND_ANY | MDB_TGT_TYPE_FUNC; 1877 1878 if (mdb_tgt_symbol_iter(mdb.m_target, MDB_TGT_OBJ_EVERY, 1879 MDB_TGT_SYMTAB, type, findsym_cb, symlist) == -1) { 1880 mdb_warn("failed to iterate over symbol table"); 1881 return (DCMD_ERR); 1882 } 1883 1884 return (DCMD_OK); 1885 } 1886 #endif /* __sparc */ 1887 1888 static int 1889 dis_str2addr(const char *s, uintptr_t *addr) 1890 { 1891 GElf_Sym sym; 1892 1893 if (s[0] >= '0' && s[0] <= '9') { 1894 *addr = (uintptr_t)mdb_strtoull(s); 1895 return (0); 1896 } 1897 1898 if (mdb_tgt_lookup_by_name(mdb.m_target, 1899 MDB_TGT_OBJ_EVERY, s, &sym, NULL) == -1) { 1900 mdb_warn("symbol '%s' not found\n", s); 1901 return (-1); 1902 } 1903 1904 *addr = (uintptr_t)sym.st_value; 1905 return (0); 1906 } 1907 1908 static int 1909 cmd_dis(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1910 { 1911 mdb_tgt_t *tgt = mdb.m_target; 1912 mdb_disasm_t *dis = mdb.m_disasm; 1913 1914 uintptr_t oaddr, naddr; 1915 mdb_tgt_as_t as; 1916 mdb_tgt_status_t st; 1917 char buf[BUFSIZ]; 1918 GElf_Sym sym; 1919 int i; 1920 1921 uint_t opt_f = FALSE; /* File-mode off by default */ 1922 uint_t opt_w = FALSE; /* Window mode off by default */ 1923 uint_t opt_a = FALSE; /* Raw-address mode off by default */ 1924 uint_t opt_b = FALSE; /* Address & symbols off by default */ 1925 uintptr_t n = -1UL; /* Length of window in instructions */ 1926 uintptr_t eaddr = 0; /* Ending address; 0 if limited by n */ 1927 1928 i = mdb_getopts(argc, argv, 1929 'f', MDB_OPT_SETBITS, TRUE, &opt_f, 1930 'w', MDB_OPT_SETBITS, TRUE, &opt_w, 1931 'a', MDB_OPT_SETBITS, TRUE, &opt_a, 1932 'b', MDB_OPT_SETBITS, TRUE, &opt_b, 1933 'n', MDB_OPT_UINTPTR, &n, NULL); 1934 1935 /* 1936 * Disgusting argument post-processing ... basically the idea is to get 1937 * the target address into addr, which we do by using the specified 1938 * expression value, looking up a string as a symbol name, or by 1939 * using the address specified as dot. 1940 */ 1941 if (i != argc) { 1942 if (argc != 0 && (argc - i) == 1) { 1943 if (argv[i].a_type == MDB_TYPE_STRING) { 1944 if (argv[i].a_un.a_str[0] == '-') 1945 return (DCMD_USAGE); 1946 1947 if (dis_str2addr(argv[i].a_un.a_str, &addr)) 1948 return (DCMD_ERR); 1949 } else 1950 addr = argv[i].a_un.a_val; 1951 } else 1952 return (DCMD_USAGE); 1953 } 1954 1955 /* 1956 * If we're not in window mode yet, and some type of arguments were 1957 * specified, see if the address corresponds nicely to a function. 1958 * If not, turn on window mode; otherwise disassemble the function. 1959 */ 1960 if (opt_w == FALSE && (argc != i || (flags & DCMD_ADDRSPEC))) { 1961 if (mdb_tgt_lookup_by_addr(tgt, addr, 1962 MDB_TGT_SYM_EXACT, buf, sizeof (buf), &sym, NULL) == 0 && 1963 GELF_ST_TYPE(sym.st_info) == STT_FUNC) { 1964 /* 1965 * If the symbol has a size then set our end address to 1966 * be the end of the function symbol we just located. 1967 */ 1968 if (sym.st_size != 0) 1969 eaddr = addr + (uintptr_t)sym.st_size; 1970 } else 1971 opt_w = TRUE; 1972 } 1973 1974 /* 1975 * Window-mode doesn't make sense in a loop. 1976 */ 1977 if (flags & DCMD_LOOP) 1978 opt_w = FALSE; 1979 1980 /* 1981 * If -n was explicit, limit output to n instructions; 1982 * otherwise set n to some reasonable default 1983 */ 1984 if (n != -1UL) 1985 eaddr = 0; 1986 else 1987 n = 10; 1988 1989 /* 1990 * If the state is IDLE (i.e. no address space), turn on -f. 1991 */ 1992 if (mdb_tgt_status(tgt, &st) == 0 && st.st_state == MDB_TGT_IDLE) 1993 opt_f = TRUE; 1994 1995 if (opt_f) 1996 as = MDB_TGT_AS_FILE; 1997 else 1998 as = MDB_TGT_AS_VIRT; 1999 2000 if (opt_w == FALSE) { 2001 n++; 2002 while ((eaddr == 0 && n-- != 0) || (addr < eaddr)) { 2003 naddr = mdb_dis_ins2str(dis, tgt, as, 2004 buf, sizeof (buf), addr); 2005 if (naddr == addr) 2006 return (DCMD_ERR); 2007 if (opt_a) 2008 mdb_printf("%-#32p%8T%s\n", addr, buf); 2009 else if (opt_b) 2010 mdb_printf("%-#10p%-#32a%8T%s\n", 2011 addr, addr, buf); 2012 else 2013 mdb_printf("%-#32a%8T%s\n", addr, buf); 2014 addr = naddr; 2015 } 2016 2017 } else { 2018 #ifdef __sparc 2019 if (addr & 0x3) { 2020 mdb_warn("address is not properly aligned\n"); 2021 return (DCMD_ERR); 2022 } 2023 #endif 2024 2025 for (oaddr = mdb_dis_previns(dis, tgt, as, addr, n); 2026 oaddr < addr; oaddr = naddr) { 2027 naddr = mdb_dis_ins2str(dis, tgt, as, 2028 buf, sizeof (buf), oaddr); 2029 if (naddr == oaddr) 2030 return (DCMD_ERR); 2031 if (opt_a) 2032 mdb_printf("%-#32p%8T%s\n", oaddr, buf); 2033 else if (opt_b) 2034 mdb_printf("%-#10p%-#32a%8T%s\n", 2035 oaddr, oaddr, buf); 2036 else 2037 mdb_printf("%-#32a%8T%s\n", oaddr, buf); 2038 } 2039 2040 if ((naddr = mdb_dis_ins2str(dis, tgt, as, 2041 buf, sizeof (buf), addr)) == addr) 2042 return (DCMD_ERR); 2043 2044 mdb_printf("%<b>"); 2045 mdb_flush(); 2046 if (opt_a) 2047 mdb_printf("%-#32p%8T%s%", addr, buf); 2048 else if (opt_b) 2049 mdb_printf("%-#10p%-#32a%8T%s", addr, addr, buf); 2050 else 2051 mdb_printf("%-#32a%8T%s%", addr, buf); 2052 mdb_printf("%</b>\n"); 2053 2054 for (addr = naddr; n-- != 0; addr = naddr) { 2055 naddr = mdb_dis_ins2str(dis, tgt, as, 2056 buf, sizeof (buf), addr); 2057 if (naddr == addr) 2058 return (DCMD_ERR); 2059 if (opt_a) 2060 mdb_printf("%-#32p%8T%s\n", addr, buf); 2061 else if (opt_b) 2062 mdb_printf("%-#10p%-#32a%8T%s\n", 2063 addr, addr, buf); 2064 else 2065 mdb_printf("%-#32a%8T%s\n", addr, buf); 2066 } 2067 } 2068 2069 mdb_set_dot(addr); 2070 return (DCMD_OK); 2071 } 2072 2073 /*ARGSUSED*/ 2074 static int 2075 walk_step(uintptr_t addr, const void *data, void *private) 2076 { 2077 mdb_printf("%lr\n", addr); 2078 return (WALK_NEXT); 2079 } 2080 2081 static int 2082 cmd_walk(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2083 { 2084 int status; 2085 2086 if (argc < 1 || argc > 2 || argv[0].a_type != MDB_TYPE_STRING || 2087 argv[argc - 1].a_type != MDB_TYPE_STRING) 2088 return (DCMD_USAGE); 2089 2090 if (argc > 1) { 2091 const char *name = argv[1].a_un.a_str; 2092 mdb_var_t *v = mdb_nv_lookup(&mdb.m_nv, name); 2093 const char *p; 2094 2095 if (v != NULL && (v->v_flags & MDB_NV_RDONLY) != 0) { 2096 mdb_warn("variable %s is read-only\n", name); 2097 return (DCMD_ABORT); 2098 } 2099 2100 if (v == NULL && (p = strbadid(name)) != NULL) { 2101 mdb_warn("'%c' may not be used in a variable " 2102 "name\n", *p); 2103 return (DCMD_ABORT); 2104 } 2105 2106 if (v == NULL && (v = mdb_nv_insert(&mdb.m_nv, 2107 name, NULL, 0, 0)) == NULL) 2108 return (DCMD_ERR); 2109 2110 /* 2111 * If there already exists a vcb for this variable, we may be 2112 * calling ::walk in a loop. We only create a vcb for this 2113 * variable on the first invocation. 2114 */ 2115 if (mdb_vcb_find(v, mdb.m_frame) == NULL) 2116 mdb_vcb_insert(mdb_vcb_create(v), mdb.m_frame); 2117 } 2118 2119 if (flags & DCMD_ADDRSPEC) 2120 status = mdb_pwalk(argv->a_un.a_str, walk_step, NULL, addr); 2121 else 2122 status = mdb_walk(argv->a_un.a_str, walk_step, NULL); 2123 2124 if (status == -1) { 2125 mdb_warn("failed to perform walk"); 2126 return (DCMD_ERR); 2127 } 2128 2129 return (DCMD_OK); 2130 } 2131 2132 static ssize_t 2133 mdb_partial_xread(void *buf, size_t nbytes, uintptr_t addr, void *arg) 2134 { 2135 ssize_t (*fp)(mdb_tgt_t *, const void *, size_t, uintptr_t) = 2136 (ssize_t (*)(mdb_tgt_t *, const void *, size_t, uintptr_t))arg; 2137 2138 return (fp(mdb.m_target, buf, nbytes, addr)); 2139 } 2140 2141 /* ARGSUSED3 */ 2142 static ssize_t 2143 mdb_partial_pread(void *buf, size_t nbytes, physaddr_t addr, void *arg) 2144 { 2145 return (mdb_tgt_pread(mdb.m_target, buf, nbytes, addr)); 2146 } 2147 2148 2149 static int 2150 cmd_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2151 { 2152 uint_t dflags = 2153 MDB_DUMP_ALIGN | MDB_DUMP_NEWDOT | MDB_DUMP_ASCII | MDB_DUMP_HEADER; 2154 uint_t phys = FALSE; 2155 uint_t file = FALSE; 2156 uintptr_t group = 4; 2157 uintptr_t width = 1; 2158 mdb_tgt_status_t st; 2159 int error; 2160 2161 if (mdb_getopts(argc, argv, 2162 'e', MDB_OPT_SETBITS, MDB_DUMP_ENDIAN, &dflags, 2163 'f', MDB_OPT_SETBITS, TRUE, &file, 2164 'g', MDB_OPT_UINTPTR, &group, 2165 'p', MDB_OPT_SETBITS, TRUE, &phys, 2166 'q', MDB_OPT_CLRBITS, MDB_DUMP_ASCII, &dflags, 2167 'r', MDB_OPT_SETBITS, MDB_DUMP_RELATIVE, &dflags, 2168 's', MDB_OPT_SETBITS, MDB_DUMP_SQUISH, &dflags, 2169 't', MDB_OPT_SETBITS, MDB_DUMP_TRIM, &dflags, 2170 'u', MDB_OPT_CLRBITS, MDB_DUMP_ALIGN, &dflags, 2171 'v', MDB_OPT_SETBITS, MDB_DUMP_PEDANT, &dflags, 2172 'w', MDB_OPT_UINTPTR, &width, NULL) != argc) 2173 return (DCMD_USAGE); 2174 2175 if ((phys && file) || 2176 (width == 0) || (width > 0x10) || 2177 (group == 0) || (group > 0x100)) 2178 return (DCMD_USAGE); 2179 2180 /* 2181 * If neither -f nor -p were specified and the state is IDLE (i.e. no 2182 * address space), turn on -p. This is so we can read large files. 2183 */ 2184 if (phys == FALSE && file == FALSE && mdb_tgt_status(mdb.m_target, 2185 &st) == 0 && st.st_state == MDB_TGT_IDLE) 2186 phys = TRUE; 2187 2188 dflags |= MDB_DUMP_GROUP(group) | MDB_DUMP_WIDTH(width); 2189 if (phys) 2190 error = mdb_dump64(mdb_get_dot(), mdb.m_dcount, dflags, 2191 mdb_partial_pread, NULL); 2192 else if (file) 2193 error = mdb_dumpptr(addr, mdb.m_dcount, dflags, 2194 mdb_partial_xread, (void *)mdb_tgt_fread); 2195 else 2196 error = mdb_dumpptr(addr, mdb.m_dcount, dflags, 2197 mdb_partial_xread, (void *)mdb_tgt_vread); 2198 2199 return (((flags & DCMD_LOOP) || (error == -1)) ? DCMD_ABORT : DCMD_OK); 2200 } 2201 2202 /*ARGSUSED*/ 2203 static int 2204 cmd_echo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2205 { 2206 if (flags & DCMD_ADDRSPEC) 2207 return (DCMD_USAGE); 2208 2209 for (; argc-- != 0; argv++) { 2210 if (argv->a_type == MDB_TYPE_STRING) 2211 mdb_printf("%s ", argv->a_un.a_str); 2212 else 2213 mdb_printf("%llr ", argv->a_un.a_val); 2214 } 2215 2216 mdb_printf("\n"); 2217 return (DCMD_OK); 2218 } 2219 2220 /*ARGSUSED*/ 2221 static int 2222 cmd_head(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2223 { 2224 uint64_t cnt = 10; 2225 const char *c; 2226 mdb_pipe_t p; 2227 2228 if (!flags & DCMD_PIPE) 2229 return (DCMD_USAGE); 2230 2231 if (argc == 1 || argc == 2) { 2232 const char *num; 2233 2234 if (argc == 1) { 2235 if (argv[0].a_type != MDB_TYPE_STRING || 2236 *argv[0].a_un.a_str != '-') 2237 return (DCMD_USAGE); 2238 2239 num = argv[0].a_un.a_str + 1; 2240 2241 } else { 2242 if (argv[0].a_type != MDB_TYPE_STRING || 2243 strcmp(argv[0].a_un.a_str, "-n") != 0) 2244 return (DCMD_USAGE); 2245 2246 num = argv[1].a_un.a_str; 2247 } 2248 2249 for (cnt = 0, c = num; *c != '\0' && isdigit(*c); c++) 2250 cnt = cnt * 10 + (*c - '0'); 2251 2252 if (*c != '\0') 2253 return (DCMD_USAGE); 2254 2255 } else if (argc != 0) { 2256 return (DCMD_USAGE); 2257 } 2258 2259 mdb_get_pipe(&p); 2260 2261 if (p.pipe_data == NULL) 2262 return (DCMD_OK); 2263 p.pipe_len = MIN(p.pipe_len, cnt); 2264 2265 if (flags & DCMD_PIPE_OUT) { 2266 mdb_set_pipe(&p); 2267 } else { 2268 while (p.pipe_len-- > 0) 2269 mdb_printf("%lx\n", *p.pipe_data++); 2270 } 2271 2272 return (DCMD_OK); 2273 } 2274 2275 static void 2276 head_help(void) 2277 { 2278 mdb_printf( 2279 "-n num\n or\n" 2280 "-num pass only the first `num' elements in the pipe.\n" 2281 "\n%<b>Note:%</b> `num' is a decimal number.\n"); 2282 } 2283 2284 static int 2285 cmd_typeset(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2286 { 2287 int add_tag = 0, del_tag = 0; 2288 const char *p; 2289 mdb_var_t *v; 2290 2291 if (argc == 0) 2292 return (cmd_vars(addr, flags, argc, argv)); 2293 2294 if (argv->a_type == MDB_TYPE_STRING && (argv->a_un.a_str[0] == '-' || 2295 argv->a_un.a_str[0] == '+')) { 2296 if (argv->a_un.a_str[1] != 't') 2297 return (DCMD_USAGE); 2298 if (argv->a_un.a_str[0] == '-') 2299 add_tag++; 2300 else 2301 del_tag++; 2302 argc--; 2303 argv++; 2304 } 2305 2306 if (!(flags & DCMD_ADDRSPEC)) 2307 addr = 0; /* set variables to zero unless explicit addr given */ 2308 2309 for (; argc-- != 0; argv++) { 2310 if (argv->a_type != MDB_TYPE_STRING) 2311 continue; 2312 2313 if (argv->a_un.a_str[0] == '-' || argv->a_un.a_str[0] == '+') { 2314 mdb_warn("ignored bad option -- %s\n", 2315 argv->a_un.a_str); 2316 continue; 2317 } 2318 2319 if ((p = strbadid(argv->a_un.a_str)) != NULL) { 2320 mdb_warn("'%c' may not be used in a variable " 2321 "name\n", *p); 2322 return (DCMD_ERR); 2323 } 2324 2325 if ((v = mdb_nv_lookup(&mdb.m_nv, argv->a_un.a_str)) == NULL) { 2326 v = mdb_nv_insert(&mdb.m_nv, argv->a_un.a_str, 2327 NULL, addr, 0); 2328 } else if (flags & DCMD_ADDRSPEC) 2329 mdb_nv_set_value(v, addr); 2330 2331 if (v != NULL) { 2332 if (add_tag) 2333 v->v_flags |= MDB_NV_TAGGED; 2334 if (del_tag) 2335 v->v_flags &= ~MDB_NV_TAGGED; 2336 } 2337 } 2338 2339 return (DCMD_OK); 2340 } 2341 2342 #ifndef _KMDB 2343 /*ARGSUSED*/ 2344 static int 2345 cmd_context(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2346 { 2347 if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 2348 return (DCMD_USAGE); 2349 2350 if (mdb_tgt_setcontext(mdb.m_target, (void *)addr) == 0) 2351 return (DCMD_OK); 2352 2353 return (DCMD_ERR); 2354 } 2355 #endif 2356 2357 /*ARGSUSED*/ 2358 static int 2359 cmd_prompt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2360 { 2361 const char *p = ""; 2362 2363 if (argc != 0) { 2364 if (argc > 1 || argv->a_type != MDB_TYPE_STRING) 2365 return (DCMD_USAGE); 2366 p = argv->a_un.a_str; 2367 } 2368 2369 (void) mdb_set_prompt(p); 2370 return (DCMD_OK); 2371 } 2372 2373 /*ARGSUSED*/ 2374 static int 2375 cmd_term(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2376 { 2377 mdb_printf("%s\n", mdb.m_termtype); 2378 2379 return (DCMD_OK); 2380 } 2381 2382 /*ARGSUSED*/ 2383 static int 2384 cmd_vtop(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2385 { 2386 physaddr_t pa; 2387 mdb_tgt_as_t as = MDB_TGT_AS_VIRT; 2388 2389 if (mdb_getopts(argc, argv, 'a', MDB_OPT_UINTPTR, (uintptr_t *)&as, 2390 NULL) != argc) 2391 return (DCMD_USAGE); 2392 2393 if (mdb_tgt_vtop(mdb.m_target, as, addr, &pa) == -1) { 2394 mdb_warn("failed to get physical mapping"); 2395 return (DCMD_ERR); 2396 } 2397 2398 if (flags & DCMD_PIPE_OUT) 2399 mdb_printf("%llr\n", pa); 2400 else 2401 mdb_printf("virtual %lr mapped to physical %llr\n", addr, pa); 2402 return (DCMD_OK); 2403 } 2404 2405 #define EVENTS_OPT_A 0x1 /* ::events -a (show all events) */ 2406 #define EVENTS_OPT_V 0x2 /* ::events -v (verbose display) */ 2407 2408 static const char * 2409 event_action(const mdb_tgt_spec_desc_t *sp) 2410 { 2411 if (!(sp->spec_flags & MDB_TGT_SPEC_HIDDEN) && sp->spec_data != NULL) 2412 return (sp->spec_data); 2413 2414 return ("-"); 2415 } 2416 2417 static void 2418 print_evsep(void) 2419 { 2420 static const char dash20[] = "--------------------"; 2421 mdb_printf("----- - -- -- -- %s%s --%s\n", dash20, dash20, dash20); 2422 } 2423 2424 /*ARGSUSED*/ 2425 static int 2426 print_event(mdb_tgt_t *t, void *private, int vid, void *data) 2427 { 2428 uint_t opts = (uint_t)(uintptr_t)private; 2429 mdb_tgt_spec_desc_t sp; 2430 char s1[41], s2[22]; 2431 const char *s2str; 2432 int visible; 2433 2434 (void) mdb_tgt_vespec_info(t, vid, &sp, s1, sizeof (s1)); 2435 visible = !(sp.spec_flags & (MDB_TGT_SPEC_HIDDEN|MDB_TGT_SPEC_DELETED)); 2436 2437 if ((opts & EVENTS_OPT_A) || visible) { 2438 int encoding = (!(sp.spec_flags & MDB_TGT_SPEC_DISABLED)) | 2439 (!(sp.spec_flags & MDB_TGT_SPEC_MATCHED) << 1); 2440 2441 char ldelim = "<<(["[encoding]; 2442 char rdelim = ">>)]"[encoding]; 2443 2444 char state = "0-+*!"[sp.spec_state]; 2445 2446 char tflag = "T "[!(sp.spec_flags & MDB_TGT_SPEC_STICKY)]; 2447 char aflag = "d "[!(sp.spec_flags & MDB_TGT_SPEC_AUTODIS)]; 2448 2449 if (sp.spec_flags & MDB_TGT_SPEC_TEMPORARY) 2450 tflag = 't'; /* TEMP takes precedence over STICKY */ 2451 if (sp.spec_flags & MDB_TGT_SPEC_AUTODEL) 2452 aflag = 'D'; /* AUTODEL takes precedence over AUTODIS */ 2453 if (sp.spec_flags & MDB_TGT_SPEC_AUTOSTOP) 2454 aflag = 's'; /* AUTOSTOP takes precedence over both */ 2455 2456 if (opts & EVENTS_OPT_V) { 2457 if (sp.spec_state == MDB_TGT_SPEC_IDLE || 2458 sp.spec_state == MDB_TGT_SPEC_ERROR) 2459 s2str = mdb_strerror(sp.spec_errno); 2460 else 2461 s2str = "-"; 2462 } else 2463 s2str = event_action(&sp); 2464 2465 if (mdb_snprintf(s2, sizeof (s2), "%s", s2str) >= sizeof (s2)) 2466 (void) strabbr(s2, sizeof (s2)); 2467 2468 if (vid > -10 && vid < 10) 2469 mdb_printf("%c%2d %c", ldelim, vid, rdelim); 2470 else 2471 mdb_printf("%c%3d%c", ldelim, vid, rdelim); 2472 2473 mdb_printf(" %c %c%c %2u %2u %-40s %-21s\n", 2474 state, tflag, aflag, sp.spec_hits, sp.spec_limit, s1, s2); 2475 2476 if (opts & EVENTS_OPT_V) { 2477 mdb_printf("%-17s%s\n", "", event_action(&sp)); 2478 print_evsep(); 2479 } 2480 } 2481 2482 return (0); 2483 } 2484 2485 /*ARGSUSED*/ 2486 static int 2487 cmd_events(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2488 { 2489 uint_t opts = 0; 2490 2491 if ((flags & DCMD_ADDRSPEC) || mdb_getopts(argc, argv, 2492 'a', MDB_OPT_SETBITS, EVENTS_OPT_A, &opts, 2493 'v', MDB_OPT_SETBITS, EVENTS_OPT_V, &opts, NULL) != argc) 2494 return (DCMD_USAGE); 2495 2496 2497 if (opts & EVENTS_OPT_V) { 2498 mdb_printf(" ID S TA HT LM %-40s %-21s\n%-17s%s\n", 2499 "Description", "Status", "", "Action"); 2500 } else { 2501 mdb_printf(" ID S TA HT LM %-40s %-21s\n", 2502 "Description", "Action"); 2503 } 2504 2505 print_evsep(); 2506 return (mdb_tgt_vespec_iter(mdb.m_target, print_event, 2507 (void *)(uintptr_t)opts)); 2508 } 2509 2510 static int 2511 tgt_status(const mdb_tgt_status_t *tsp) 2512 { 2513 const char *format; 2514 char buf[BUFSIZ]; 2515 2516 if (tsp->st_flags & MDB_TGT_BUSY) 2517 return (DCMD_OK); 2518 2519 if (tsp->st_pc != 0) { 2520 if (mdb_dis_ins2str(mdb.m_disasm, mdb.m_target, MDB_TGT_AS_VIRT, 2521 buf, sizeof (buf), tsp->st_pc) != tsp->st_pc) 2522 format = "target stopped at:\n%-#16a%8T%s\n"; 2523 else 2524 format = "target stopped at %a:\n"; 2525 mdb_warn(format, tsp->st_pc, buf); 2526 } 2527 2528 switch (tsp->st_state) { 2529 case MDB_TGT_IDLE: 2530 mdb_warn("target is idle\n"); 2531 break; 2532 case MDB_TGT_RUNNING: 2533 if (tsp->st_flags & MDB_TGT_DSTOP) 2534 mdb_warn("target is running, stop directive pending\n"); 2535 else 2536 mdb_warn("target is running\n"); 2537 break; 2538 case MDB_TGT_STOPPED: 2539 if (tsp->st_pc == 0) 2540 mdb_warn("target is stopped\n"); 2541 break; 2542 case MDB_TGT_UNDEAD: 2543 mdb_warn("target has terminated\n"); 2544 break; 2545 case MDB_TGT_DEAD: 2546 mdb_warn("target is a core dump\n"); 2547 break; 2548 case MDB_TGT_LOST: 2549 mdb_warn("target is no longer under debugger control\n"); 2550 break; 2551 } 2552 2553 mdb_set_dot(tsp->st_pc); 2554 return (DCMD_OK); 2555 } 2556 2557 /* 2558 * mdb continue/step commands take an optional signal argument, but the 2559 * corresponding kmdb versions don't. 2560 */ 2561 #ifdef _KMDB 2562 #define CONT_MAXARGS 0 /* no optional SIG argument */ 2563 #else 2564 #define CONT_MAXARGS 1 2565 #endif 2566 2567 /*ARGSUSED*/ 2568 static int 2569 cmd_cont_common(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv, 2570 int (*t_cont)(mdb_tgt_t *, mdb_tgt_status_t *), const char *name) 2571 { 2572 mdb_tgt_t *t = mdb.m_target; 2573 mdb_tgt_status_t st; 2574 int sig = 0; 2575 2576 if ((flags & DCMD_ADDRSPEC) || argc > CONT_MAXARGS) 2577 return (DCMD_USAGE); 2578 2579 if (argc > 0) { 2580 if (argv->a_type == MDB_TYPE_STRING) { 2581 if (proc_str2sig(argv->a_un.a_str, &sig) == -1) { 2582 mdb_warn("invalid signal name -- %s\n", 2583 argv->a_un.a_str); 2584 return (DCMD_USAGE); 2585 } 2586 } else 2587 sig = (int)(intmax_t)argv->a_un.a_val; 2588 } 2589 2590 (void) mdb_tgt_status(t, &st); 2591 2592 if (st.st_state == MDB_TGT_IDLE && mdb_tgt_run(t, 0, NULL) == -1) { 2593 if (errno != EMDB_TGT) 2594 mdb_warn("failed to create new target"); 2595 return (DCMD_ERR); 2596 } 2597 2598 if (sig != 0 && mdb_tgt_signal(t, sig) == -1) { 2599 mdb_warn("failed to post signal %d", sig); 2600 return (DCMD_ERR); 2601 } 2602 2603 if (st.st_state == MDB_TGT_IDLE && t_cont == &mdb_tgt_step) { 2604 (void) mdb_tgt_status(t, &st); 2605 return (tgt_status(&st)); 2606 } 2607 2608 if (t_cont(t, &st) == -1) { 2609 if (errno != EMDB_TGT) 2610 mdb_warn("failed to %s target", name); 2611 return (DCMD_ERR); 2612 } 2613 2614 return (tgt_status(&st)); 2615 } 2616 2617 static int 2618 cmd_step(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2619 { 2620 int (*func)(mdb_tgt_t *, mdb_tgt_status_t *) = &mdb_tgt_step; 2621 const char *name = "single-step"; 2622 2623 if (argc > 0 && argv->a_type == MDB_TYPE_STRING) { 2624 if (strcmp(argv->a_un.a_str, "out") == 0) { 2625 func = &mdb_tgt_step_out; 2626 name = "step (out)"; 2627 argv++; 2628 argc--; 2629 } else if (strcmp(argv->a_un.a_str, "branch") == 0) { 2630 func = &mdb_tgt_step_branch; 2631 name = "step (branch)"; 2632 argv++; 2633 argc--; 2634 } else if (strcmp(argv->a_un.a_str, "over") == 0) { 2635 func = &mdb_tgt_next; 2636 name = "step (over)"; 2637 argv++; 2638 argc--; 2639 } 2640 } 2641 2642 return (cmd_cont_common(addr, flags, argc, argv, func, name)); 2643 } 2644 2645 static int 2646 cmd_step_out(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2647 { 2648 return (cmd_cont_common(addr, flags, argc, argv, 2649 &mdb_tgt_step_out, "step (out)")); 2650 } 2651 2652 static int 2653 cmd_next(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2654 { 2655 return (cmd_cont_common(addr, flags, argc, argv, 2656 &mdb_tgt_next, "step (over)")); 2657 } 2658 2659 static int 2660 cmd_cont(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2661 { 2662 return (cmd_cont_common(addr, flags, argc, argv, 2663 &mdb_tgt_continue, "continue")); 2664 } 2665 2666 #ifndef _KMDB 2667 /*ARGSUSED*/ 2668 static int 2669 cmd_run(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2670 { 2671 if (flags & DCMD_ADDRSPEC) 2672 return (DCMD_USAGE); 2673 2674 if (mdb_tgt_run(mdb.m_target, argc, argv) == -1) { 2675 if (errno != EMDB_TGT) 2676 mdb_warn("failed to create new target"); 2677 return (DCMD_ERR); 2678 } 2679 return (cmd_cont(NULL, 0, 0, NULL)); 2680 } 2681 #endif 2682 2683 /* 2684 * To simplify the implementation of :d, :z, and ::delete, we use the sp 2685 * parameter to store the criteria for what to delete. If spec_base is set, 2686 * we delete vespecs with a matching address. If spec_id is set, we delete 2687 * vespecs with a matching id. Otherwise, we delete all vespecs. We bump 2688 * sp->spec_size so the caller can tell how many vespecs were deleted. 2689 */ 2690 static int 2691 ve_delete(mdb_tgt_t *t, mdb_tgt_spec_desc_t *sp, int vid, void *data) 2692 { 2693 mdb_tgt_spec_desc_t spec; 2694 int status = -1; 2695 2696 if (vid < 0) 2697 return (0); /* skip over target implementation events */ 2698 2699 if (sp->spec_base != NULL) { 2700 (void) mdb_tgt_vespec_info(t, vid, &spec, NULL, 0); 2701 if (sp->spec_base - spec.spec_base < spec.spec_size) 2702 status = mdb_tgt_vespec_delete(t, vid); 2703 } else if (sp->spec_id == 0) { 2704 (void) mdb_tgt_vespec_info(t, vid, &spec, NULL, 0); 2705 if (!(spec.spec_flags & MDB_TGT_SPEC_STICKY)) 2706 status = mdb_tgt_vespec_delete(t, vid); 2707 } else if (sp->spec_id == vid) 2708 status = mdb_tgt_vespec_delete(t, vid); 2709 2710 if (status == 0) { 2711 if (data != NULL) 2712 strfree(data); 2713 sp->spec_size++; 2714 } 2715 2716 return (0); 2717 } 2718 2719 static int 2720 ve_delete_spec(mdb_tgt_spec_desc_t *sp) 2721 { 2722 (void) mdb_tgt_vespec_iter(mdb.m_target, 2723 (mdb_tgt_vespec_f *)ve_delete, sp); 2724 2725 if (sp->spec_size == 0) { 2726 if (sp->spec_id != 0 || sp->spec_base != NULL) 2727 mdb_warn("no traced events matched description\n"); 2728 } 2729 2730 return (DCMD_OK); 2731 } 2732 2733 /*ARGSUSED*/ 2734 static int 2735 cmd_zapall(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2736 { 2737 mdb_tgt_spec_desc_t spec; 2738 2739 if ((flags & DCMD_ADDRSPEC) || argc != 0) 2740 return (DCMD_USAGE); 2741 2742 bzero(&spec, sizeof (spec)); 2743 return (ve_delete_spec(&spec)); 2744 } 2745 2746 static int 2747 cmd_delete(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2748 { 2749 mdb_tgt_spec_desc_t spec; 2750 2751 if (((flags & DCMD_ADDRSPEC) && argc > 0) || argc > 1) 2752 return (DCMD_USAGE); 2753 2754 bzero(&spec, sizeof (spec)); 2755 2756 if (flags & DCMD_ADDRSPEC) 2757 spec.spec_base = addr; 2758 else if (argc == 0) 2759 spec.spec_base = mdb_get_dot(); 2760 else if (argv->a_type == MDB_TYPE_STRING && 2761 strcmp(argv->a_un.a_str, "all") != 0) 2762 spec.spec_id = (int)(intmax_t)strtonum(argv->a_un.a_str, 10); 2763 else if (argv->a_type == MDB_TYPE_IMMEDIATE) 2764 spec.spec_id = (int)(intmax_t)argv->a_un.a_val; 2765 2766 return (ve_delete_spec(&spec)); 2767 } 2768 2769 static void 2770 srcexec_file_help(void) 2771 { 2772 mdb_printf( 2773 "The library of macros delivered with previous versions of Solaris have been\n" 2774 "superseded by the dcmds and walkers provided by MDB. See ::help for\n" 2775 "commands that can be used to list the available dcmds and walkers.\n" 2776 "\n" 2777 "Aliases have been created for several of the more popular macros. To see\n" 2778 "the list of aliased macros, as well as their native MDB equivalents,\n" 2779 "type $M.\n"); 2780 2781 #ifdef _KMDB 2782 mdb_printf( 2783 "When invoked, the $< and $<< dcmds will consult the macro alias list. If an\n" 2784 "alias cannot be found, an attempt will be made to locate a data type whose\n" 2785 "name corresponds to the requested macro. If such a type can be found, it\n" 2786 "will be displayed using the ::print dcmd.\n"); 2787 #else 2788 mdb_printf( 2789 "When invoked, the $< and $<< dcmds will first attempt to locate a macro with\n" 2790 "the indicated name. If no macro can be found, and if no alias exists for\n" 2791 "this macro, an attempt will be made to locate a data type whose name\n" 2792 "corresponds to the requested macro. If such a type can be found, it will be\n" 2793 "displayed using the ::print dcmd.\n"); 2794 #endif 2795 } 2796 2797 static void 2798 events_help(void) 2799 { 2800 mdb_printf("Options:\n" 2801 "-a show all events, including internal debugger events\n" 2802 "-v show verbose display, including inactivity reason\n" 2803 "\nOutput Columns:\n" 2804 "ID decimal event specifier id number:\n" 2805 " [ ] event tracing is enabled\n" 2806 " ( ) event tracing is disabled\n" 2807 " < > target is currently stopped on this type of event\n\n" 2808 "S event specifier state:\n" 2809 " - event specifier is idle (not applicable yet)\n" 2810 " + event specifier is active\n" 2811 " * event specifier is armed (target program running)\n" 2812 " ! error occurred while attempting to arm event\n\n" 2813 "TA event specifier flags:\n" 2814 " t event specifier is temporary (delete at next stop)\n" 2815 " T event specifier is sticky (::delete all has no effect)\n" 2816 " d event specifier will be disabled when HT = LM\n" 2817 " D event specifier will be deleted when HT = LM\n" 2818 " s target will automatically stop when HT = LM\n\n" 2819 "HT hit count (number of times event has occurred)\n" 2820 "LM hit limit (limit for autostop, disable, delete)\n"); 2821 } 2822 2823 static void 2824 dump_help(void) 2825 { 2826 mdb_printf( 2827 "-e adjust for endianness\n" 2828 " (assumes 4-byte words; use -g to change word size)\n" 2829 #ifdef _KMDB 2830 "-f no effect\n" 2831 #else 2832 "-f dump from object file\n" 2833 #endif 2834 "-g n display bytes in groups of n\n" 2835 " (default is 4; n must be a power of 2, divide line width)\n" 2836 "-p dump from physical memory\n" 2837 "-q don't print ASCII\n" 2838 "-r use relative numbering (automatically sets -u)\n" 2839 "-s elide repeated lines\n" 2840 "-t only read from and display contents of specified addresses\n" 2841 " (default is to read and print entire lines)\n" 2842 "-u un-align output\n" 2843 " (default is to align output at paragraph boundary)\n" 2844 "-w n display n 16-byte paragraphs per line\n" 2845 " (default is 1, maximum is 16)\n"); 2846 } 2847 2848 /* 2849 * Table of built-in dcmds associated with the root 'mdb' module. Future 2850 * expansion of this program should be done here, or through the external 2851 * loadable module interface. 2852 */ 2853 const mdb_dcmd_t mdb_dcmd_builtins[] = { 2854 2855 /* 2856 * dcmds common to both mdb and kmdb 2857 */ 2858 { ">", "variable-name", "assign variable", cmd_assign_variable }, 2859 { "/", "fmt-list", "format data from virtual as", cmd_print_core }, 2860 { "\\", "fmt-list", "format data from physical as", cmd_print_phys }, 2861 { "@", "fmt-list", "format data from physical as", cmd_print_phys }, 2862 { "=", "fmt-list", "format immediate value", cmd_print_value }, 2863 { "$<", "macro-name", "replace input with macro", 2864 cmd_exec_file, srcexec_file_help }, 2865 { "$<<", "macro-name", "source macro", 2866 cmd_src_file, srcexec_file_help}, 2867 { "$%", NULL, NULL, cmd_quit }, 2868 { "$?", NULL, "print status and registers", cmd_notsup }, 2869 { "$a", NULL, NULL, cmd_algol }, 2870 { "$b", "[-av]", "list traced software events", 2871 cmd_events, events_help }, 2872 { "$c", "?[cnt]", "print stack backtrace", cmd_notsup }, 2873 { "$C", "?[cnt]", "print stack backtrace", cmd_notsup }, 2874 { "$d", NULL, "get/set default output radix", cmd_radix }, 2875 { "$D", "?[mode,...]", NULL, cmd_dbmode }, 2876 { "$e", NULL, "print listing of global symbols", cmd_globals }, 2877 { "$f", NULL, "print listing of source files", cmd_files }, 2878 { "$m", "?[name]", "print address space mappings", cmd_mappings }, 2879 { "$M", NULL, "list macro aliases", cmd_macalias_list }, 2880 { "$P", "[prompt]", "set debugger prompt string", cmd_prompt }, 2881 { "$q", NULL, "quit debugger", cmd_quit }, 2882 { "$Q", NULL, "quit debugger", cmd_quit }, 2883 { "$r", NULL, "print general-purpose registers", cmd_notsup }, 2884 { "$s", NULL, "get/set symbol matching distance", cmd_symdist }, 2885 { "$v", NULL, "print non-zero variables", cmd_nzvars }, 2886 { "$V", "[mode]", "get/set disassembly mode", cmd_dismode }, 2887 { "$w", NULL, "get/set output page width", cmd_pgwidth }, 2888 { "$W", NULL, "re-open target in write mode", cmd_reopen }, 2889 { ":a", ":[cmd...]", "set read access watchpoint", cmd_oldwpr }, 2890 { ":b", ":[cmd...]", "breakpoint at the specified address", cmd_oldbp }, 2891 { ":d", "?[id|all]", "delete traced software events", cmd_delete }, 2892 { ":p", ":[cmd...]", "set execute access watchpoint", cmd_oldwpx }, 2893 { ":S", NULL, NULL, cmd_step }, 2894 { ":w", ":[cmd...]", "set write access watchpoint", cmd_oldwpw }, 2895 { ":z", NULL, "delete all traced software events", cmd_zapall }, 2896 { "array", ":[type count] [variable]", "print each array element's " 2897 "address", cmd_array }, 2898 { "bp", "?[+/-dDestT] [-c cmd] [-n count] sym ...", "breakpoint at the " 2899 "specified addresses or symbols", cmd_bp, bp_help }, 2900 { "dcmds", NULL, "list available debugger commands", cmd_dcmds }, 2901 { "delete", "?[id|all]", "delete traced software events", cmd_delete }, 2902 { "dis", "?[-abfw] [-n cnt] [addr]", "disassemble near addr", cmd_dis }, 2903 { "disasms", NULL, "list available disassemblers", cmd_disasms }, 2904 { "dismode", "[mode]", "get/set disassembly mode", cmd_dismode }, 2905 { "dmods", "[-l] [mod]", "list loaded debugger modules", cmd_dmods }, 2906 { "dump", "?[-eqrstu] [-f|-p] [-g bytes] [-w paragraphs]", 2907 "dump memory from specified address", cmd_dump, dump_help }, 2908 { "echo", "args ...", "echo arguments", cmd_echo }, 2909 { "enum", "?[-x] enum [name]", "print an enumeration", cmd_enum }, 2910 { "eval", "command", "evaluate the specified command", cmd_eval }, 2911 { "events", "[-av]", "list traced software events", 2912 cmd_events, events_help }, 2913 { "evset", "?[+/-dDestT] [-c cmd] [-n count] id ...", 2914 "set software event specifier attributes", cmd_evset, evset_help }, 2915 { "files", "[object]", "print listing of source files", cmd_files }, 2916 #ifdef __sparc 2917 { "findsym", "?[-g] [symbol|addr ...]", "search for symbol references " 2918 "in all known functions", cmd_findsym, NULL }, 2919 #endif 2920 { "formats", NULL, "list format specifiers", cmd_formats }, 2921 { "grep", "?expr", "print dot if expression is true", cmd_grep }, 2922 { "head", "-num|-n num", "limit number of elements in pipe", cmd_head, 2923 head_help }, 2924 { "help", "[cmd]", "list commands/command help", cmd_help }, 2925 { "list", "?type member [variable]", 2926 "walk list using member as link pointer", cmd_list }, 2927 { "map", "?expr", "print dot after evaluating expression", cmd_map }, 2928 { "mappings", "?[name]", "print address space mappings", cmd_mappings }, 2929 { "nm", "?[-DPdghnopuvx] [-f format] [-t types] [object]", 2930 "print symbols", cmd_nm, nm_help }, 2931 { "nmadd", ":[-fo] [-e end] [-s size] name", 2932 "add name to private symbol table", cmd_nmadd, nmadd_help }, 2933 { "nmdel", "name", "remove name from private symbol table", cmd_nmdel }, 2934 { "obey", NULL, NULL, cmd_obey }, 2935 { "objects", "[-v]", "print load objects information", cmd_objects }, 2936 { "offsetof", "type member", "print the offset of a given struct " 2937 "or union member", cmd_offsetof }, 2938 { "print", "?[-aCdhiLptx] [-c lim] [-l lim] [type] [member|offset ...]", 2939 "print the contents of a data structure", cmd_print, print_help }, 2940 { "regs", NULL, "print general purpose registers", cmd_notsup }, 2941 { "set", "[-wF] [+/-o opt] [-s dist] [-I path] [-L path] [-P prompt]", 2942 "get/set debugger properties", cmd_set }, 2943 { "showrev", "[-pv]", "print version information", cmd_showrev }, 2944 { "sizeof", "type", "print the size of a type", cmd_sizeof }, 2945 { "stack", "?[cnt]", "print stack backtrace", cmd_notsup }, 2946 { "stackregs", "?", "print stack backtrace and registers", 2947 cmd_notsup }, 2948 { "status", NULL, "print summary of current target", cmd_notsup }, 2949 { "term", NULL, "display current terminal type", cmd_term }, 2950 { "typeset", "[+/-t] var ...", "set variable attributes", cmd_typeset }, 2951 { "unset", "[name ...]", "unset variables", cmd_unset }, 2952 { "vars", "[-npt]", "print listing of variables", cmd_vars }, 2953 { "version", NULL, "print debugger version string", cmd_version }, 2954 { "vtop", ":[-a as]", "print physical mapping of virtual address", 2955 cmd_vtop }, 2956 { "walk", "?name [variable]", "walk data structure", cmd_walk }, 2957 { "walkers", NULL, "list available walkers", cmd_walkers }, 2958 { "whatis", ":[-aikqv]", "given an address, return information", 2959 cmd_whatis, whatis_help }, 2960 { "whence", "[-v] name ...", "show source of walk or dcmd", cmd_which }, 2961 { "which", "[-v] name ...", "show source of walk or dcmd", cmd_which }, 2962 { "xdata", NULL, "print list of external data buffers", cmd_xdata }, 2963 2964 #ifdef _KMDB 2965 /* 2966 * dcmds specific to kmdb, or which have kmdb-specific arguments 2967 */ 2968 { "?", "fmt-list", "format data from virtual as", cmd_print_core }, 2969 { ":c", NULL, "continue target execution", cmd_cont }, 2970 { ":e", NULL, "step target over next instruction", cmd_next }, 2971 { ":s", NULL, "single-step target to next instruction", cmd_step }, 2972 { ":u", NULL, "step target out of current function", cmd_step_out }, 2973 { "cont", NULL, "continue target execution", cmd_cont }, 2974 { "load", "[-sd] module", "load debugger module", cmd_load, load_help }, 2975 { "next", NULL, "step target over next instruction", cmd_next }, 2976 { "quit", "[-u]", "quit debugger", cmd_quit, quit_help }, 2977 { "step", "[ over | out ]", 2978 "single-step target to next instruction", cmd_step }, 2979 { "unload", "[-d] module", "unload debugger module", cmd_unload, 2980 unload_help }, 2981 { "wp", ":[+/-dDelstT] [-rwx] [-pi] [-c cmd] [-n count] [-L size]", 2982 "set a watchpoint at the specified address", cmd_wp, wp_help }, 2983 2984 #else 2985 /* 2986 * dcmds specific to mdb, or which have mdb-specific arguments 2987 */ 2988 { "?", "fmt-list", "format data from object file", cmd_print_object }, 2989 { "$>", "[file]", "log session to a file", cmd_old_log }, 2990 { "$g", "?", "get/set C++ demangling options", cmd_demflags }, 2991 { "$G", NULL, "enable/disable C++ demangling support", cmd_demangle }, 2992 { "$i", NULL, "print signals that are ignored", cmd_notsup }, 2993 { "$l", NULL, "print the representative thread's lwp id", cmd_notsup }, 2994 { "$p", ":", "change debugger target context", cmd_context }, 2995 { "$x", NULL, "print floating point registers", cmd_notsup }, 2996 { "$X", NULL, "print floating point registers", cmd_notsup }, 2997 { "$y", NULL, "print floating point registers", cmd_notsup }, 2998 { "$Y", NULL, "print floating point registers", cmd_notsup }, 2999 { ":A", "?[core|pid]", "attach to process or core file", cmd_notsup }, 3000 { ":c", "[SIG]", "continue target execution", cmd_cont }, 3001 { ":e", "[SIG]", "step target over next instruction", cmd_next }, 3002 { ":i", ":", "ignore signal (delete all matching events)", cmd_notsup }, 3003 { ":k", NULL, "forcibly kill and release target", cmd_notsup }, 3004 { ":t", "?[+/-dDestT] [-c cmd] [-n count] SIG ...", "stop on delivery " 3005 "of the specified signals", cmd_sigbp, sigbp_help }, 3006 { ":r", "[ args ... ]", "run a new target process", cmd_run }, 3007 { ":R", NULL, "release the previously attached process", cmd_notsup }, 3008 { ":s", "[SIG]", "single-step target to next instruction", cmd_step }, 3009 { ":u", "[SIG]", "step target out of current function", cmd_step_out }, 3010 { "attach", "?[core|pid]", 3011 "attach to process or core file", cmd_notsup }, 3012 { "cat", "[file ...]", "concatenate and display files", cmd_cat }, 3013 { "cont", "[SIG]", "continue target execution", cmd_cont }, 3014 { "context", ":", "change debugger target context", cmd_context }, 3015 { "dem", "name ...", "demangle C++ symbol names", cmd_demstr }, 3016 { "fltbp", "?[+/-dDestT] [-c cmd] [-n count] fault ...", 3017 "stop on machine fault", cmd_fltbp, fltbp_help }, 3018 { "fpregs", NULL, "print floating point registers", cmd_notsup }, 3019 { "kill", NULL, "forcibly kill and release target", cmd_notsup }, 3020 { "load", "[-s] module", "load debugger module", cmd_load, load_help }, 3021 { "log", "[-d | [-e] file]", "log session to a file", cmd_log }, 3022 { "next", "[SIG]", "step target over next instruction", cmd_next }, 3023 { "quit", NULL, "quit debugger", cmd_quit }, 3024 { "release", NULL, 3025 "release the previously attached process", cmd_notsup }, 3026 { "run", "[ args ... ]", "run a new target process", cmd_run }, 3027 { "sigbp", "?[+/-dDestT] [-c cmd] [-n count] SIG ...", "stop on " 3028 "delivery of the specified signals", cmd_sigbp, sigbp_help }, 3029 { "step", "[ over | out ] [SIG]", 3030 "single-step target to next instruction", cmd_step }, 3031 { "sysbp", "?[+/-dDestT] [-io] [-c cmd] [-n count] syscall ...", 3032 "stop on entry or exit from system call", cmd_sysbp, sysbp_help }, 3033 { "unload", "module", "unload debugger module", cmd_unload }, 3034 { "wp", ":[+/-dDelstT] [-rwx] [-c cmd] [-n count] [-L size]", 3035 "set a watchpoint at the specified address", cmd_wp, wp_help }, 3036 #endif 3037 3038 { NULL } 3039 }; 3040