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